diff --git a/.gitignore b/.gitignore
index ce22fa007..0a9599378 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ perl/Makefile.config
 /scripts/nix-copy-closure
 /scripts/nix-reduce-build
 /scripts/nix-http-export.cgi
+/scripts/nix-profile-daemon.sh
 
 # /src/libexpr/
 /src/libexpr/lexer-tab.cc
diff --git a/Makefile b/Makefile
index 5d8e990cc..c867823fc 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,8 @@ makefiles = \
   misc/launchd/local.mk \
   misc/upstart/local.mk \
   doc/manual/local.mk \
-  tests/local.mk
+  tests/local.mk \
+  tests/plugins/local.mk
 
 GLOBAL_CXXFLAGS += -std=c++14 -g -Wall -include config.h
 
diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index fff7994f2..cede6db3c 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -742,6 +742,33 @@ builtins.fetchurl {
   
 
 
+  
+    plugin-files
+    
+      
+        A list of plugin files to be loaded by Nix. Each of these
+        files will be dlopened by Nix, allowing them to affect
+        execution through static initialization. In particular, these
+        plugins may construct static instances of RegisterPrimOp to
+        add new primops to the expression language,
+        RegisterStoreImplementation to add new store implementations,
+        and RegisterCommand to add new subcommands to the
+        nix command. See the constructors for those
+        types for more details.
+      
+      
+	Since these files are loaded into the same address space as
+        Nix itself, they must be DSOs compatible with the instance of
+        Nix running at the time (i.e. compiled against the same
+        headers, not linked to any incompatible libraries). They
+        should not be linked to any Nix libs directly, as those will
+        be available already at load time.
+      
+    
+
+  
+
+
 
 
 
diff --git a/doc/manual/release-notes/rl-2.0.xml b/doc/manual/release-notes/rl-2.0.xml
index 32cdb1d0c..effd2e39d 100644
--- a/doc/manual/release-notes/rl-2.0.xml
+++ b/doc/manual/release-notes/rl-2.0.xml
@@ -389,6 +389,13 @@ configureFlags = "--prefix=${placeholder "out"} --includedir=${placeholder "dev"
     
   
 
+  
+    
+      Nix can now be extended with plugins. See the documentation of
+      the 'plugin-files' option for more details.
+    
+  
+
 
 
 Some features were removed:
diff --git a/mk/libraries.mk b/mk/libraries.mk
index 3cd7a5310..14c95fa91 100644
--- a/mk/libraries.mk
+++ b/mk/libraries.mk
@@ -45,6 +45,11 @@ endif
 # - $(1)_INSTALL_DIR: the directory where the library will be
 #   installed.  Defaults to $(libdir).
 #
+# - $(1)_EXCLUDE_FROM_LIBRARY_LIST: if defined, the library will not
+#   be automatically marked as a dependency of the top-level all
+#   target andwill not be listed in the make help output. This is
+#   useful for libraries built solely for testing, for example.
+#
 # - BUILD_SHARED_LIBS: if equal to ‘1’, a dynamic library will be
 #   built, otherwise a static library.
 define build-library
@@ -149,7 +154,9 @@ define build-library
   $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn)))
   -include $$($(1)_DEPS)
 
+  ifndef $(1)_EXCLUDE_FROM_LIBRARY_LIST
   libs-list += $$($(1)_PATH)
+  endif
   clean-files += $$(_d)/*.a $$(_d)/*.$(SO_EXT) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS)
   dist-files += $$(_srcs)
 endef
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index c6e75e8cc..dbf8fe1b8 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -64,6 +64,8 @@ int main (int argc, char * * argv)
 
         settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
 
+        initPlugins();
+
         auto store = openStore().cast();
 
         /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index 1dcc4f0ac..8e4861232 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -22,6 +22,7 @@ public:
 
 int handleExceptions(const string & programName, std::function fun);
 
+/* Don't forget to call initPlugins() after settings are initialized! */
 void initNix();
 
 void parseCmdLine(int argc, char * * argv,
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index d3c96ddd6..21ab0e629 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -6,6 +6,7 @@
 #include 
 #include