diff --git a/.gitignore b/.gitignore
index 65493af99aa9eb3a0663afc1acdadfd53f485092..6a4aa6a96b586e04392cd6c064b7a7f48f7f780e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
 .cache
 /*.log
 /.vscode
+/.idea
diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index deadf948b8ffa2eb4b9bb2670a7b6774d5e3a403..10a65d0233af14b2f537cf15c2e06f2a27b752a3 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -128,6 +128,15 @@ const options = [
     stage: 'branch',
     type: 'boolean',
   },
+  // Bot administration
+  {
+    name: 'exposeEnv',
+    description:
+      'Enable this to expose bot process.env to repositories for npmrc substitution and package installation',
+    stage: 'global',
+    type: 'boolean',
+    default: false,
+  },
   {
     name: 'platform',
     description: 'Platform type of repository',
diff --git a/lib/manager/npm/registry.js b/lib/manager/npm/registry.js
index c18f6d1dd9618f14a04b582b2cf431f863c3a0e0..1a5aeca088753ff740c34856fe5f89ec011d4b41 100644
--- a/lib/manager/npm/registry.js
+++ b/lib/manager/npm/registry.js
@@ -30,14 +30,35 @@ function resetCache() {
   resetMemCache();
 }
 
-function setNpmrc(input) {
+function setNpmrc(input, exposeEnv = false) {
+  logger.debug('setNpmrc()');
   if (input) {
     npmrc = ini.parse(input);
+    if (!exposeEnv) {
+      return;
+    }
+    for (const key in npmrc) {
+      if (Object.prototype.hasOwnProperty.call(npmrc, key)) {
+        npmrc[key] = envReplace(npmrc[key]);
+      }
+    }
   } else {
     npmrc = null;
   }
 }
 
+function envReplace(value, env = process.env) {
+  const ENV_EXPR = /(\\*)\$\{([^}]+)\}/g;
+
+  return value.replace(ENV_EXPR, (match, esc, envVarName) => {
+    if (env[envVarName] === undefined) {
+      logger.warn('Failed to replace env in config: ' + match);
+      throw new Error('env-replace');
+    }
+    return env[envVarName];
+  });
+}
+
 async function getDependency(name) {
   logger.trace(`getDependency(${name})`);
   if (memcache[name]) {
diff --git a/lib/workers/branch/lock-files.js b/lib/workers/branch/lock-files.js
index d913b4ba95592d4123c866ee527e785335aa45bf..3bc2377563917e6b50140d2535b3a51ddd95cc1d 100644
--- a/lib/workers/branch/lock-files.js
+++ b/lib/workers/branch/lock-files.js
@@ -299,11 +299,18 @@ async function getUpdatedLockFiles(config) {
   await module.exports.writeExistingFiles(config);
   await module.exports.writeUpdatedPackageFiles(config);
 
+  const env =
+    config.global && config.global.exposeEnv
+      ? process.env
+      : { PATH: process.env.PATH };
+  env.NODE_ENV = 'dev';
+
   for (const lockFileDir of dirs.packageLockFileDirs) {
     logger.debug(`Generating package-lock.json for ${lockFileDir}`);
     const lockFileName = upath.join(lockFileDir, 'package-lock.json');
     const res = await npm.generateLockFile(
-      upath.join(config.tmpDir.path, lockFileDir)
+      upath.join(config.tmpDir.path, lockFileDir),
+      env
     );
     if (res.error) {
       lockFileErrors.push({
@@ -331,7 +338,8 @@ async function getUpdatedLockFiles(config) {
     logger.debug(`Generating yarn.lock for ${lockFileDir}`);
     const lockFileName = upath.join(lockFileDir, 'yarn.lock');
     const res = await yarn.generateLockFile(
-      upath.join(config.tmpDir.path, lockFileDir)
+      upath.join(config.tmpDir.path, lockFileDir),
+      env
     );
     if (res.error) {
       lockFileErrors.push({
@@ -359,7 +367,8 @@ async function getUpdatedLockFiles(config) {
     logger.debug(`Generating shrinkwrap.yaml for ${lockFileDir}`);
     const lockFileName = upath.join(lockFileDir, 'shrinkwrap.yaml');
     const res = await pnpm.generateLockFile(
-      upath.join(config.tmpDir.path, lockFileDir)
+      upath.join(config.tmpDir.path, lockFileDir),
+      env
     );
     if (res.error) {
       lockFileErrors.push({
diff --git a/lib/workers/branch/npm.js b/lib/workers/branch/npm.js
index 4c1e41bb67d18e8a1adf5c805dda2fd4ca9792c9..4f497cabfb80f576f6e24203e385dd3db602aff3 100644
--- a/lib/workers/branch/npm.js
+++ b/lib/workers/branch/npm.js
@@ -7,7 +7,7 @@ module.exports = {
   generateLockFile,
 };
 
-async function generateLockFile(tmpDir) {
+async function generateLockFile(tmpDir, env) {
   logger.debug(`Spawning npm install to create ${tmpDir}/package-lock.json`);
   let lockFile = null;
   let stdout;
@@ -58,7 +58,7 @@ async function generateLockFile(tmpDir) {
     ({ stdout, stderr } = await exec(cmd, {
       cwd: tmpDir,
       shell: true,
-      env: { NODE_ENV: 'dev', PATH: process.env.PATH },
+      env,
     }));
     logger.debug(`npm stdout:\n${stdout}`);
     logger.debug(`npm stderr:\n${stderr}`);
diff --git a/lib/workers/branch/pnpm.js b/lib/workers/branch/pnpm.js
index 1032c10c286ab20c67bfb4b4d1c3281086c88a3c..f843220c359baf0ee89205b36c7a59a1b21fe973 100644
--- a/lib/workers/branch/pnpm.js
+++ b/lib/workers/branch/pnpm.js
@@ -7,7 +7,7 @@ module.exports = {
   generateLockFile,
 };
 
-async function generateLockFile(tmpDir) {
+async function generateLockFile(tmpDir, env) {
   logger.debug(`Spawning pnpm install to create ${tmpDir}/shrinkwrap.yaml`);
   let lockFile = null;
   let stdout;
@@ -61,7 +61,7 @@ async function generateLockFile(tmpDir) {
     ({ stdout, stderr } = await exec(cmd, {
       cwd: tmpDir,
       shell: true,
-      env: { NODE_ENV: 'dev', PATH: process.env.PATH },
+      env,
     }));
     logger.debug(`pnpm stdout:\n${stdout}`);
     logger.debug(`pnpm stderr:\n${stderr}`);
diff --git a/lib/workers/branch/yarn.js b/lib/workers/branch/yarn.js
index e7b9f1ae804fd36c50ceb7e0105506e950b85703..cfa5d481c61b00359f07e1a2efe3afcfefb45680 100644
--- a/lib/workers/branch/yarn.js
+++ b/lib/workers/branch/yarn.js
@@ -7,7 +7,7 @@ module.exports = {
   generateLockFile,
 };
 
-async function generateLockFile(tmpDir) {
+async function generateLockFile(tmpDir, env) {
   logger.debug(`Spawning yarn install to create ${tmpDir}/yarn.lock`);
   let lockFile = null;
   let stdout;
@@ -60,7 +60,7 @@ async function generateLockFile(tmpDir) {
     ({ stdout, stderr } = await exec(cmd, {
       cwd: tmpDir,
       shell: true,
-      env: { NODE_ENV: 'dev', PATH: process.env.PATH },
+      env,
     }));
     logger.debug(`yarn stdout:\n${stdout}`);
     logger.debug(`yarn stderr:\n${stderr}`);
diff --git a/lib/workers/global/index.js b/lib/workers/global/index.js
index 458cec4c3927952ea586c7adb6218a5e2cd8dfb6..51ff763792c1fcf25d13f3a5364db11aad6c544c 100644
--- a/lib/workers/global/index.js
+++ b/lib/workers/global/index.js
@@ -25,6 +25,13 @@ async function start() {
         'No repositories found - did you want to run with flag --autodiscover?'
       );
     }
+    // Move global variables that we need to use later
+    const importGlobals = ['exposeEnv'];
+    config.global = {};
+    importGlobals.forEach(key => {
+      config.global[key] = config[key];
+      delete config[key];
+    });
     // Iterate through repositories sequentially
     for (let index = 0; index < config.repositories.length; index += 1) {
       const repoConfig = module.exports.getRepositoryConfig(config, index);
diff --git a/lib/workers/package-file/index.js b/lib/workers/package-file/index.js
index b26fb31397e03dadf062c77a8c3d4ebe08edc604..88423b02c9d5542d7d10c1bf267ac82c39701254 100644
--- a/lib/workers/package-file/index.js
+++ b/lib/workers/package-file/index.js
@@ -35,7 +35,10 @@ async function renovatePackageFile(packageFileConfig) {
   logger.debug('renovatePakageFile()');
   if (config.npmrc) {
     logger.debug('Setting .npmrc');
-    npmApi.setNpmrc(config.npmrc);
+    npmApi.setNpmrc(
+      config.npmrc,
+      config.global ? config.global.exposeEnv : false
+    );
   }
   let upgrades = [];
   logger.info(`Processing package file`);
diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js
index 2d7f0b63199a9e0004a02d6cdbca6816b5b827ff..44ab838085baaa804a9c7e11a0a3f3f016718394 100644
--- a/lib/workers/repository/index.js
+++ b/lib/workers/repository/index.js
@@ -14,6 +14,7 @@ module.exports = {
 
 async function renovateRepository(repoConfig, token, loop = 1) {
   let config = { ...repoConfig, branchList: [] };
+  config.global = config.global || {};
   logger.setMeta({ repository: config.repository });
   logger.info('Renovating repository');
   logger.trace({ config, loop }, 'renovateRepository()');
diff --git a/lib/workers/repository/init/apis.js b/lib/workers/repository/init/apis.js
index 3cf04ce5849d101e2af3da235e091370f0c1b0e4..13c74d289182941e5b89bba7e00770880470fad7 100644
--- a/lib/workers/repository/init/apis.js
+++ b/lib/workers/repository/init/apis.js
@@ -27,7 +27,10 @@ async function initApis(input, token) {
   config = await getPlatformConfig(config);
   config.npmrc = config.npmrc || (await platform.getFile('.npmrc'));
   npmApi.resetMemCache();
-  npmApi.setNpmrc(config.npmrc);
+  npmApi.setNpmrc(
+    config.npmrc,
+    config.global ? config.global.exposeEnv : false
+  );
   return config;
 }
 
diff --git a/test/manager/npm/__snapshots__/registry.spec.js.snap b/test/manager/npm/__snapshots__/registry.spec.js.snap
index 2220264b22e7844f6496bfd13912609dd4514a79..943cf847f4ddc384ada36ffc7136cb014dc33e97 100644
--- a/test/manager/npm/__snapshots__/registry.spec.js.snap
+++ b/test/manager/npm/__snapshots__/registry.spec.js.snap
@@ -34,6 +34,23 @@ Object {
 }
 `;
 
+exports[`api/npm should replace any environment variable in npmrc 1`] = `
+Object {
+  "dist-tags": Object {
+    "latest": "0.0.1",
+  },
+  "homepage": undefined,
+  "name": undefined,
+  "renovate-config": undefined,
+  "repositoryUrl": undefined,
+  "versions": Object {
+    "0.0.1": Object {
+      "time": "",
+    },
+  },
+}
+`;
+
 exports[`api/npm should send an authorization header if provided 1`] = `
 Object {
   "dist-tags": Object {
diff --git a/test/manager/npm/registry.spec.js b/test/manager/npm/registry.spec.js
index 498085728aa71a0749c488a6229bcc9fd3b600d7..a8f61c4ec8378295a8a6693de5e665dbe072cd46 100644
--- a/test/manager/npm/registry.spec.js
+++ b/test/manager/npm/registry.spec.js
@@ -162,4 +162,28 @@ describe('api/npm', () => {
     const res = await npm.getDependency('foobar');
     expect(res).toMatchSnapshot();
   });
+  it('should replace any environment variable in npmrc', async () => {
+    nock('https://registry.from-env.com')
+      .get('/foobar')
+      .reply(200, npmResponse);
+    process.env.REGISTRY = 'https://registry.from-env.com';
+    /* eslint-disable */
+    npm.setNpmrc('registry=${REGISTRY}', true);
+    /* eslint-enable */
+    const res = await npm.getDependency('foobar');
+    expect(res).toMatchSnapshot();
+  });
+  it('should throw error if necessary env var is not present', () => {
+    let e;
+    try {
+      /* eslint-disable */
+      npm.setNpmrc('registry=${REGISTRY_MISSING}', true);
+      /* eslint-enable */
+    } catch (err) {
+      e = err;
+    }
+    /* eslint-disable */
+    expect(e.message).toBe('env-replace');
+    /* eslint-enable */
+  });
 });