diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index aee81a704ccfd173d867988bedf98a2a6991b978..d13666d615a68c5b9475c5ef1c534c2d86a46dcf 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -298,6 +298,15 @@ const options = [
     mergeable: true,
     cli: false,
   },
+  {
+    name: 'engines',
+    description: 'Configuration specifically for `package.json`>`engines`',
+    stage: 'packageFile',
+    type: 'json',
+    default: {},
+    mergeable: true,
+    cli: false,
+  },
   // depType
   {
     name: 'ignoreDeps',
diff --git a/lib/manager/npm/engines.js b/lib/manager/npm/engines.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ae10e628ae0e7555da42032bc3731dcb89f25be
--- /dev/null
+++ b/lib/manager/npm/engines.js
@@ -0,0 +1,43 @@
+const semver = require('semver');
+const { getRepoReleases, semverSort } = require('../../datasource/github');
+
+async function renovateEngines(config) {
+  const { currentVersion, depName: dependency } = config;
+  logger.debug({ dependency, currentVersion }, 'Found engines');
+  if (config.depName !== 'node') {
+    logger.debug('Skipping non-node engine');
+    return [];
+  }
+  logger.info('Checking node engine');
+  if (!semver.valid(currentVersion)) {
+    logger.info({ currentVersion }, 'Skipping non-pinned node version');
+    return [];
+  }
+  const newReleases = (await getRepoReleases('nodejs/node'))
+    .map(release => release.replace(/^v/, ''))
+    .filter(release => semver.major(currentVersion) === semver.major(release))
+    .filter(release => semver.gt(release, currentVersion))
+    .sort(semverSort);
+  if (newReleases.length) {
+    logger.info({ newReleases }, 'Found newer Node releases');
+  } else {
+    return [];
+  }
+  const newVersion = newReleases.pop();
+  return [
+    {
+      type:
+        semver.major(currentVersion) !== semver.major(newVersion)
+          ? 'major'
+          : 'minor',
+      newVersion,
+      newVersionMajor: semver.major(newVersion),
+      newVersionMinor: semver.minor(newVersion),
+      changeLogFromVersion: currentVersion,
+      changeLogToVersion: newVersion,
+      repositoryUrl: 'https://github.com/nodejs/node',
+    },
+  ];
+}
+
+module.exports = { renovateEngines };
diff --git a/lib/manager/npm/package.js b/lib/manager/npm/package.js
index 5255a5c095f9a91a23afc75a61f23af9243eeeb4..c0a653635c629eb34f838fd3be99c021204a4373 100644
--- a/lib/manager/npm/package.js
+++ b/lib/manager/npm/package.js
@@ -1,11 +1,15 @@
 const npmApi = require('./registry');
 const versions = require('../../workers/package/versions');
+const { renovateEngines } = require('./engines');
 
 module.exports = {
   getPackageUpdates,
 };
 
 async function getPackageUpdates(config) {
+  if (config.depType === 'engines') {
+    return renovateEngines(config);
+  }
   let results = [];
   if (config.currentVersion.startsWith('file:')) {
     logger.debug(
diff --git a/lib/workers/package-file/index.js b/lib/workers/package-file/index.js
index caf91e31761ee59e034f42dafa4a8e0fccc22c2a..76dd9a8ef129c7289a81eea28a98ccaaa90252d9 100644
--- a/lib/workers/package-file/index.js
+++ b/lib/workers/package-file/index.js
@@ -96,6 +96,7 @@ async function renovatePackageFile(packageFileConfig) {
     'devDependencies',
     'optionalDependencies',
     'peerDependencies',
+    'engines',
   ];
   const depTypeConfigs = depTypes.map(depType => {
     const depTypeConfig = configParser.mergeChildConfig(config, {
diff --git a/lib/workers/pr/index.js b/lib/workers/pr/index.js
index cccab2c7ce6b8de5b8f174194f5596b0a44b7152..c0b4d1153fdf219f6772e10a0e16cd5954017e6d 100644
--- a/lib/workers/pr/index.js
+++ b/lib/workers/pr/index.js
@@ -110,11 +110,14 @@ async function ensurePr(prConfig) {
     }
     processedUpgrades.push(upgradeKey);
 
-    const logJSON = await changelogHelper.getChangeLogJSON(
-      upgrade.depName,
-      upgrade.changeLogFromVersion,
-      upgrade.changeLogToVersion
-    );
+    let logJSON;
+    if (upgrade.depType !== 'engines') {
+      logJSON = await changelogHelper.getChangeLogJSON(
+        upgrade.depName,
+        upgrade.changeLogFromVersion,
+        upgrade.changeLogToVersion
+      );
+    }
     if (logJSON) {
       upgrade.githubName = logJSON.project.github;
       upgrade.hasReleaseNotes = logJSON.hasReleaseNotes;
diff --git a/test/manager/npm/engines.spec.js b/test/manager/npm/engines.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..2c65d9c9e74a0941af1df43881af4b89a72fccb2
--- /dev/null
+++ b/test/manager/npm/engines.spec.js
@@ -0,0 +1,37 @@
+const engines = require('../../../lib/manager/npm/engines');
+const { getRepoReleases } = require('../../../lib/datasource/github');
+
+jest.mock('../../../lib/datasource/github');
+
+describe('manager/npm/engines', () => {
+  let config;
+  beforeEach(() => {
+    config = {
+      depName: 'node',
+    };
+  });
+  it('skips non-pinned versions', async () => {
+    config.currentVersion = '8';
+    const res = await engines.renovateEngines(config);
+    expect(res).toEqual([]);
+  });
+  it('returns empty', async () => {
+    config.currentVersion = '8.9.0';
+    getRepoReleases.mockReturnValueOnce([]);
+    const res = await engines.renovateEngines(config);
+    expect(res).toEqual([]);
+  });
+  it('filters v', async () => {
+    config.currentVersion = '8.9.0';
+    getRepoReleases.mockReturnValueOnce(['v8.0.0', 'v8.9.1']);
+    const res = await engines.renovateEngines(config);
+    expect(res).toHaveLength(1);
+    expect(res[0].newVersion).toEqual('8.9.1');
+  });
+  it('skips major versions', async () => {
+    config.currentVersion = '8.9.0';
+    getRepoReleases.mockReturnValueOnce(['v9.4.0']);
+    const res = await engines.renovateEngines(config);
+    expect(res).toHaveLength(0);
+  });
+});
diff --git a/test/manager/npm/package.spec.js b/test/manager/npm/package.spec.js
index eb77e142bbf2f262d5d838978bd46435cf5ba176..ac1a4b0c8c08b8ca0c9879a5ea4c3a0077b8ba69 100644
--- a/test/manager/npm/package.spec.js
+++ b/test/manager/npm/package.spec.js
@@ -17,6 +17,11 @@ describe('lib/workers/package/npm', () => {
         currentVersion: '1.0.0',
       };
     });
+    it('calls engines function', async () => {
+      config.depType = 'engines';
+      const res = await npm.getPackageUpdates(config);
+      expect(res).toHaveLength(0);
+    });
     it('returns if using a file reference', async () => {
       config.currentVersion = 'file:../sibling/package.json';
       const res = await npm.getPackageUpdates(config);
diff --git a/website/docs/_posts/2017-10-05-configuration-options.md b/website/docs/_posts/2017-10-05-configuration-options.md
index 70191f4e31bb5268511b510b64bdd584433a7c71..b26149b3d3d1f78052340826bc72f9da458a7aac 100644
--- a/website/docs/_posts/2017-10-05-configuration-options.md
+++ b/website/docs/_posts/2017-10-05-configuration-options.md
@@ -262,6 +262,17 @@ A configuration object containing strings encrypted with Renovate's public key.
 
 See https://renovateapp.com/docs/deep-dives/private-modules for details on how this is used to encrypt npm tokens.
 
+## engines
+
+Configuration specific for `package.json > engines`.
+
+| name    | value  |
+| ------- | ------ |
+| type    | object |
+| default | {}     |
+
+Extend this if you wish to configure rules specifically for `engines` definitions. Currently only `node` is supported.
+
 ## excludePackageNames
 
 A list of package names inside a package rule which are to be excluded/ignored.