diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000000..5c5ae7d7630
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,43 @@
+{
+  env: {
+    development: {
+      plugins: [
+        [
+          "transform-async-to-module-method",
+          {
+            module: "bluebird-lst-c",
+            method: "coroutine"
+          }
+        ],
+        "transform-es2015-parameters",
+        "transform-es2015-spread",
+        "transform-es2015-destructuring",
+        "array-includes",
+        [
+          "transform-inline-imports-commonjs",
+          {
+            excludeModules: ["path"]
+          }
+        ],
+      ],
+    },
+    test: {
+      sourceMaps: "inline",
+      plugins: [
+        [
+          "transform-async-to-module-method",
+          {
+            module: "bluebird-lst-c",
+            method: "coroutine"
+          }
+        ],
+        [
+          "transform-inline-imports-commonjs",
+          {
+            excludeModules: ["path"]
+          }
+        ],
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
index f9db70b81e0..1038133a841 100644
--- a/.idea/codeStyleSettings.xml
+++ b/.idea/codeStyleSettings.xml
@@ -20,6 +20,9 @@
           <option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
           <option name="SPACES_WITHIN_IMPORTS" value="true" />
         </JSCodeStyleSettings>
+        <JSON>
+          <option name="ARRAY_WRAPPING" value="0" />
+        </JSON>
         <TypeScriptCodeStyleSettings>
           <option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
           <option name="IMPORTS_WRAP" value="0" />
diff --git a/.idea/dictionaries/develar.xml b/.idea/dictionaries/develar.xml
index dd56977cc42..f0a00dae295 100644
--- a/.idea/dictionaries/develar.xml
+++ b/.idea/dictionaries/develar.xml
@@ -16,6 +16,8 @@
       <w>appxmanifest</w>
       <w>archiver</w>
       <w>archs</w>
+      <w>armv</w>
+      <w>asar</w>
       <w>aspx</w>
       <w>atexit</w>
       <w>atime</w>
@@ -40,6 +42,7 @@
       <w>debian</w>
       <w>depcheck</w>
       <w>devel</w>
+      <w>develar</w>
       <w>devmode</w>
       <w>difflet</w>
       <w>digester</w>
@@ -72,6 +75,7 @@
       <w>hklm</w>
       <w>homedir</w>
       <w>hrtime</w>
+      <w>icns</w>
       <w>icnsutils</w>
       <w>icnv</w>
       <w>iconset</w>
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 3d4082833f6..1feb5064e3b 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -6,6 +6,9 @@
     <inspection_tool class="JSIgnoredPromiseFromCall" enabled="true" level="ERROR" enabled_by_default="true" />
     <inspection_tool class="JSLastCommaInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
     <inspection_tool class="JSLastCommaInObjectLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
+    <inspection_tool class="JsonStandardCompliance" enabled="true" level="ERROR" enabled_by_default="true">
+      <scope name="json5" level="INFORMATION" enabled="true" />
+    </inspection_tool>
     <inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
       <option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
       <option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
diff --git a/.idea/scopes/json5.xml b/.idea/scopes/json5.xml
new file mode 100644
index 00000000000..e11bd99491d
--- /dev/null
+++ b/.idea/scopes/json5.xml
@@ -0,0 +1,3 @@
+<component name="DependencyValidationManager">
+  <scope name="json5" pattern="file:.babelrc" />
+</component>
\ No newline at end of file
diff --git a/docs/Options.md b/docs/Options.md
index 752caa430c1..6c0a2dee412 100644
--- a/docs/Options.md
+++ b/docs/Options.md
@@ -58,7 +58,6 @@ Don't customize paths to background and icon, — just follow conventions.
 | Name | Description
 | --- | ---
 | **build** | <a name="DevMetadata-build"></a>See [.build](#BuildMetadata).
-| directories | <a name="DevMetadata-directories"></a>See [.directories](#MetadataDirectories)
 
 <a name="BuildMetadata"></a>
 ## `.build`
@@ -91,6 +90,8 @@ Don't customize paths to background and icon, — just follow conventions.
 | electronDist | <a name="BuildMetadata-electronDist"></a>The path to custom Electron build (e.g. `~/electron/out/R`). Only macOS supported, file issue if need for Linux or Windows.
 | electronDownload | <a name="BuildMetadata-electronDownload"></a>The [electron-download](https://github.com/electron-userland/electron-download#usage) options.
 | publish | <a name="BuildMetadata-publish"></a>See [.build.publish](#PublishConfiguration).
+| forceCodeSigning | <a name="BuildMetadata-forceCodeSigning"></a>Whether to fail if application will be not signed (to prevent unsigned app if code signing configuration is not correct).
+| directories | <a name="BuildMetadata-directories"></a>See [.directories](#MetadataDirectories)
 
 <a name="DmgOptions"></a>
 ### `.build.dmg`
diff --git a/docs/programmaticUsage.js b/docs/programmaticUsage.js
index d658d95d3ad..093d67a56f7 100644
--- a/docs/programmaticUsage.js
+++ b/docs/programmaticUsage.js
@@ -6,7 +6,7 @@ const builder = require("electron-builder")
 builder.build({
   platform: [builder.Platform.MAC],
   "//": "platform, arch and other properties, see PackagerOptions in the node_modules/electron-builder/out/electron-builder.d.ts",
-  devMetadata: {
+  config: {
     "//": "build and other properties, see https://goo.gl/5jVxoO"
   }
 })
diff --git a/package.json b/package.json
index 80cfe46c9a5..2fd95f158cb 100644
--- a/package.json
+++ b/package.json
@@ -120,51 +120,6 @@
     "typescript": "^2.1.4",
     "whitespace": "^2.1.0"
   },
-  "babel": {
-    "plugins": [
-      [
-        "transform-async-to-module-method",
-        {
-          "module": "bluebird-lst-c",
-          "method": "coroutine"
-        }
-      ],
-      "transform-es2015-parameters",
-      "transform-es2015-spread",
-      "transform-es2015-destructuring",
-      "array-includes",
-      [
-        "transform-inline-imports-commonjs",
-        {
-          "excludeModules": [
-            "path"
-          ]
-        }
-      ]
-    ],
-    "env": {
-      "test": {
-        "sourceMaps": "inline",
-        "plugins": [
-          [
-            "transform-async-to-module-method",
-            {
-              "module": "bluebird-lst-c",
-              "method": "coroutine"
-            }
-          ],
-          [
-            "transform-inline-imports-commonjs",
-            {
-              "excludeModules": [
-                "path"
-              ]
-            }
-          ]
-        ]
-      }
-    }
-  },
   "jest": {
     "testEnvironment": "node",
     "testPathDirs": [
diff --git a/src/appInfo.ts b/src/appInfo.ts
index 8b9a686718f..7db028c4d55 100644
--- a/src/appInfo.ts
+++ b/src/appInfo.ts
@@ -1,4 +1,4 @@
-import { DevMetadata, AppMetadata } from "./metadata"
+import { DevMetadata, AppMetadata, BuildMetadata } from "./metadata"
 import { warn } from "./util/log"
 import { smarten } from "./platformPackager"
 import { isEmptyOrSpaces } from "./util/util"
@@ -15,10 +15,14 @@ export class AppInfo {
   readonly productName: string
   readonly productFilename: string
 
+  private get config(): BuildMetadata {
+    return this.devMetadata.build
+  }
+
   constructor(public metadata: AppMetadata, private devMetadata: DevMetadata, buildVersion?: string | null) {
     this.version = metadata.version!
 
-    this.buildNumber = (<any>this.devMetadata.build)["build-version"] || process.env.TRAVIS_BUILD_NUMBER || process.env.APPVEYOR_BUILD_NUMBER || process.env.CIRCLE_BUILD_NUM || process.env.BUILD_NUMBER
+    this.buildNumber = (<any>this.config)["build-version"] || process.env.TRAVIS_BUILD_NUMBER || process.env.APPVEYOR_BUILD_NUMBER || process.env.CIRCLE_BUILD_NUM || process.env.BUILD_NUMBER
 
     if (isEmptyOrSpaces(buildVersion)) {
       buildVersion = this.version
@@ -31,7 +35,7 @@ export class AppInfo {
       this.buildVersion = buildVersion!
     }
 
-    this.productName = getProductName(this.metadata, this.devMetadata)
+    this.productName = this.config.productName || metadata.productName || metadata.name
     this.productFilename = sanitizeFileName(this.productName)
   }
 
@@ -45,13 +49,13 @@ export class AppInfo {
   }
 
   get id(): string {
-    let appId = this.devMetadata.build["app-bundle-id"]
+    let appId = this.config["app-bundle-id"]
     if (appId != null) {
       warn("app-bundle-id is deprecated, please use appId")
     }
 
-    if (this.devMetadata.build.appId != null) {
-      appId = this.devMetadata.build.appId
+    if (this.config.appId != null) {
+      appId = this.config.appId
     }
 
     const generateDefaultAppId = () => {
@@ -72,7 +76,7 @@ export class AppInfo {
   }
 
   get copyright(): string {
-    const copyright = this.devMetadata.build.copyright
+    const copyright = this.config.copyright
     if (copyright != null) {
       return copyright
     }
@@ -80,19 +84,12 @@ export class AppInfo {
   }
 
   async computePackageUrl(): Promise<string | null> {
-    const url = this.metadata.homepage || this.devMetadata.homepage
+    const url = this.metadata.homepage
     if (url != null) {
       return url
     }
 
     const info = await getRepositoryInfo(this.metadata, this.devMetadata)
-    if (info != null) {
-      return `https://github.com/${info.user}/${info.project}`
-    }
-    return null
+    return info == null ? null : `https://github.com/${info.user}/${info.project}`
   }
-}
-
-function getProductName(metadata: AppMetadata, devMetadata: DevMetadata) {
-  return devMetadata.build.productName || metadata.productName || metadata.name
 }
\ No newline at end of file
diff --git a/src/cli/install-app-deps.ts b/src/cli/install-app-deps.ts
index 26679a6a9a9..e374fe7de29 100644
--- a/src/cli/install-app-deps.ts
+++ b/src/cli/install-app-deps.ts
@@ -1,5 +1,5 @@
 #! /usr/bin/env node
-import { computeDefaultAppDirectory, getElectronVersion, use } from "../util/util"
+import { computeDefaultAppDirectory, getElectronVersion, use, getDirectoriesConfig } from "../util/util"
 import { printErrorAndExit } from "../util/promise"
 import * as path from "path"
 import BluebirdPromise from "bluebird-lst-c"
@@ -19,7 +19,7 @@ async function main() {
 
   const devMetadata: DevMetadata = await readPackageJson(devPackageFile)
   const results: Array<string> = await BluebirdPromise.all([
-    computeDefaultAppDirectory(projectDir, use(devMetadata.directories, it => it!.app)),
+    computeDefaultAppDirectory(projectDir, use(getDirectoriesConfig(devMetadata), it => it!.app)),
     getElectronVersion(devMetadata, devPackageFile)
   ])
 
diff --git a/src/macPackager.ts b/src/macPackager.ts
index b68219bd612..a98cab583b6 100644
--- a/src/macPackager.ts
+++ b/src/macPackager.ts
@@ -32,11 +32,11 @@ export default class MacPackager extends PlatformPackager<MacOptions> {
   }
 
   protected prepareAppInfo(appInfo: AppInfo): AppInfo {
-    return new AppInfo(appInfo.metadata, this.devMetadata, this.platformSpecificBuildOptions.bundleVersion)
+    return new AppInfo(appInfo.metadata, this.info.devMetadata, this.platformSpecificBuildOptions.bundleVersion)
   }
 
   async getIconPath(): Promise<string | null> {
-    let iconPath = this.platformSpecificBuildOptions.icon || this.devMetadata.build.icon
+    let iconPath = this.platformSpecificBuildOptions.icon || this.config.icon
     if (iconPath != null && !iconPath.endsWith(".icns")) {
       iconPath += ".icns"
     }
@@ -82,7 +82,7 @@ export default class MacPackager extends PlatformPackager<MacOptions> {
 
     if (hasMas) {
       const appOutDir = path.join(outDir, "mas")
-      const masBuildOptions = deepAssign({}, this.platformSpecificBuildOptions, (<any>this.devMetadata.build).mas)
+      const masBuildOptions = deepAssign({}, this.platformSpecificBuildOptions, (<any>this.config).mas)
       await this.doPack(outDir, appOutDir, "mas", arch, masBuildOptions)
       await this.sign(appOutDir, masBuildOptions)
     }
@@ -113,7 +113,7 @@ export default class MacPackager extends PlatformPackager<MacOptions> {
 
       if (name == null) {
         let message = `App is not signed: cannot find valid ${isMas ? '"3rd Party Mac Developer Application" identity' : `"Developer ID Application" identity or custom non-Apple code signing certificate`}, see https://github.com/electron-userland/electron-builder/wiki/Code-Signing`
-        if (isMas) {
+        if (isMas || this.platformSpecificBuildOptions.forceCodeSigning) {
           throw new Error(message)
         }
         else {
@@ -172,7 +172,7 @@ export default class MacPackager extends PlatformPackager<MacOptions> {
   }
 
   async findInstallerIdentity(isMas: boolean, keychainName: string | n): Promise<string> {
-    const targetSpecificOptions: MacOptions = (<any>this.devMetadata.build)[isMas ? "mas" : "pkg"] || this.platformSpecificBuildOptions
+    const targetSpecificOptions: MacOptions = (<any>this.config)[isMas ? "mas" : "pkg"] || this.platformSpecificBuildOptions
     const name = isMas ? "3rd Party Mac Developer Installer" : "Developer ID Installer"
     let installerName = await findIdentity(name, targetSpecificOptions.identity, keychainName)
     if (installerName != null) {
diff --git a/src/metadata.ts b/src/metadata.ts
index 713c2c4e840..ce8b78cc59b 100755
--- a/src/metadata.ts
+++ b/src/metadata.ts
@@ -58,17 +58,6 @@ export interface DevMetadata extends Metadata {
    See [.build](#BuildMetadata).
    */
   readonly build: BuildMetadata
-
-  // deprecated
-  readonly homepage?: string | null
-
-  // deprecated
-  readonly license?: string | null
-
-  /*
-   See [.directories](#MetadataDirectories)
-   */
-  readonly directories?: MetadataDirectories | null
 }
 
 export interface RepositoryInfo {
@@ -241,6 +230,16 @@ export interface BuildMetadata {
   See [.build.publish](#PublishConfiguration).
    */
   readonly publish?: Publish
+
+  /*
+  Whether to fail if application will be not signed (to prevent unsigned app if code signing configuration is not correct).
+   */
+  readonly forceCodeSigning?: boolean
+
+  /*
+   See [.directories](#MetadataDirectories)
+   */
+  readonly directories?: MetadataDirectories | null
 }
 
 export interface AfterPackContext {
@@ -344,6 +343,8 @@ export interface PlatformSpecificBuildOptions {
   readonly fileAssociations?: Array<FileAssociation> | FileAssociation
 
   readonly publish?: Publish
+
+  readonly forceCodeSigning?: boolean
 }
 
 export class Platform {
diff --git a/src/packager.ts b/src/packager.ts
index c9890ba93cb..2c3b11a871c 100644
--- a/src/packager.ts
+++ b/src/packager.ts
@@ -1,9 +1,9 @@
 import * as path from "path"
-import { computeDefaultAppDirectory, getElectronVersion, use, exec, isEmptyOrSpaces } from "./util/util"
+import { computeDefaultAppDirectory, getElectronVersion, use, exec, isEmptyOrSpaces, getDirectoriesConfig } from "./util/util"
 import { all, executeFinally } from "./util/promise"
 import { EventEmitter } from "events"
 import BluebirdPromise from "bluebird-lst-c"
-import { AppMetadata, DevMetadata, Platform, Arch } from "./metadata"
+import { AppMetadata, DevMetadata, Platform, Arch, BuildMetadata } from "./metadata"
 import { PlatformPackager, BuildInfo, ArtifactCreated } from "./platformPackager"
 import { WinPackager } from "./winPackager"
 import * as errorMessages from "./errorMessages"
@@ -28,8 +28,13 @@ export class Packager implements BuildInfo {
   appDir: string
 
   metadata: AppMetadata
+
   devMetadata: DevMetadata
 
+  get config(): BuildMetadata {
+    return this.devMetadata.build
+  }
+
   isTwoPackageJsonProjectLayoutUsed = true
 
   electronVersion: string
@@ -55,12 +60,21 @@ export class Packager implements BuildInfo {
   }
 
   async build(): Promise<Map<Platform, Map<String, Target>>> {
-    const devPackageFile = this.devPackageFile
-
     const extraMetadata = this.options.extraMetadata
     const extraBuildMetadata = extraMetadata == null ? null : extraMetadata.build
 
-    this.devMetadata = deepAssign(await readPackageJson(devPackageFile), this.options.devMetadata)
+    let devMetadataFromOptions = this.options.devMetadata
+    const buildConfigFromOptions = this.options.config
+    if (buildConfigFromOptions != null) {
+      if (devMetadataFromOptions != null) {
+        throw new Error("devMetadata and config cannot be used in conjunction")
+      }
+      devMetadataFromOptions = {build: buildConfigFromOptions}
+    }
+
+    const devPackageFile = this.devPackageFile
+    this.devMetadata = deepAssign(await readPackageJson(devPackageFile), devMetadataFromOptions)
+
     if (extraMetadata != null) {
       if (extraBuildMetadata != null) {
         deepAssign(this.devMetadata, {build: extraBuildMetadata})
@@ -72,7 +86,7 @@ export class Packager implements BuildInfo {
       }
     }
 
-    this.appDir = await computeDefaultAppDirectory(this.projectDir, use(this.devMetadata.directories, it => it!.app))
+    this.appDir = await computeDefaultAppDirectory(this.projectDir, use(getDirectoriesConfig(this.devMetadata), it => it!.app))
 
     this.isTwoPackageJsonProjectLayoutUsed = this.appDir !== this.projectDir
 
@@ -91,7 +105,7 @@ export class Packager implements BuildInfo {
     }
 
     this.checkMetadata(appPackageFile, devPackageFile)
-    checkConflictingOptions(this.devMetadata.build)
+    checkConflictingOptions(this.config)
 
     this.electronVersion = await getElectronVersion(this.devMetadata, devPackageFile)
 
@@ -102,7 +116,7 @@ export class Packager implements BuildInfo {
 
   private async doBuild(cleanupTasks: Array<() => Promise<any>>): Promise<Map<Platform, Map<String, Target>>> {
     const distTasks: Array<Promise<any>> = []
-    const outDir = path.resolve(this.projectDir, use(this.devMetadata.directories, it => it!.output) || "dist")
+    const outDir = path.resolve(this.projectDir, use(getDirectoriesConfig(this.devMetadata), it => it!.output) || "dist")
 
     const platformToTarget: Map<Platform, Map<String, Target>> = new Map()
     // custom packager - don't check wine
@@ -193,7 +207,7 @@ export class Packager implements BuildInfo {
       }
     }
 
-    const build = <any>this.devMetadata.build
+    const build = <any>this.config
     if (build == null) {
       throw new Error(util.format(errorMessages.buildIsMissed, devAppPackageFile))
     }
@@ -220,10 +234,6 @@ export class Packager implements BuildInfo {
         throw new Error(util.format(errorMessages.nameInBuildSpecified, appPackageFile))
       }
 
-      if (build.directories != null) {
-        throw new Error(`'directories' in the 'build' is not correct. Please move 'directories' from 'build' to root`)
-      }
-
       if (build.prune != null) {
         warn("prune is deprecated — development dependencies are never copied in any case")
       }
@@ -231,7 +241,7 @@ export class Packager implements BuildInfo {
   }
 
   private async installAppDependencies(platform: Platform, arch: Arch): Promise<any> {
-    const options = this.devMetadata.build
+    const options = this.config
     if (options.nodeGypRebuild === true) {
       log(`Executing node-gyp rebuild for arch ${Arch[arch]}`)
       await exec(process.platform === "win32" ? "node-gyp.cmd" : "node-gyp", ["rebuild"], {
diff --git a/src/packager/dirPackager.ts b/src/packager/dirPackager.ts
index 30c86f54edc..60202e47ea3 100644
--- a/src/packager/dirPackager.ts
+++ b/src/packager/dirPackager.ts
@@ -33,10 +33,10 @@ function subOptionWarning (properties: any, optionName: any, parameter: any, val
 }
 
 export async function unpackElectron(packager: PlatformPackager<any>, out: string, platform: string, arch: string, electronVersion: string) {
-  const electronDist = packager.devMetadata.build.electronDist
+  const electronDist = packager.config.electronDist
   if (electronDist == null) {
     const zipPath = (await BluebirdPromise.all<any>([
-      downloadElectron(createDownloadOpts(packager.devMetadata.build, platform, arch, electronVersion)),
+      downloadElectron(createDownloadOpts(packager.config, platform, arch, electronVersion)),
       emptyDir(out)
     ]))[0]
 
diff --git a/src/packager/mac.ts b/src/packager/mac.ts
index 8ce289bc0ad..ea03d2c281d 100644
--- a/src/packager/mac.ts
+++ b/src/packager/mac.ts
@@ -37,7 +37,7 @@ export async function createApp(packager: PlatformPackager<any>, appOutDir: stri
   const helperEHPlistFilename = path.join(frameworksPath, "Electron Helper EH.app", "Contents", "Info.plist")
   const helperNPPlistFilename = path.join(frameworksPath, "Electron Helper NP.app", "Contents", "Info.plist")
 
-  const buildMetadata = packager.devMetadata.build!
+  const buildMetadata = packager.config!
   const fileContents: Array<string> = await BluebirdPromise.map([appPlistFilename, helperPlistFilename, helperEHPlistFilename, helperNPPlistFilename, (<any>buildMetadata)["extend-info"]], it => it == null ? it : readFile(it, "utf8"))
   const appPlist = parsePlist(fileContents[0])
   const helperPlist = parsePlist(fileContents[1])
diff --git a/src/platformPackager.ts b/src/platformPackager.ts
index 7829a6893c8..5789dd77491 100644
--- a/src/platformPackager.ts
+++ b/src/platformPackager.ts
@@ -1,8 +1,8 @@
-import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, Arch, FileAssociation } from "./metadata"
+import { AppMetadata, DevMetadata, Platform, PlatformSpecificBuildOptions, Arch, FileAssociation, BuildMetadata } from "./metadata"
 import BluebirdPromise from "bluebird-lst-c"
 import * as path from "path"
 import { readdir, remove, rename } from "fs-extra-p"
-import { use, isEmptyOrSpaces, asArray, debug } from "./util/util"
+import { use, isEmptyOrSpaces, asArray, debug, getDirectoriesConfig } from "./util/util"
 import { Packager } from "./packager"
 import { AsarOptions } from "asar-electron-builder"
 import { Minimatch } from "minimatch"
@@ -41,6 +41,11 @@ export interface PackagerOptions {
    */
   readonly devMetadata?: DevMetadata
 
+  /*
+   See [.build](#BuildMetadata).
+   */
+  readonly config?: BuildMetadata
+
   /**
    * The same as [application package.json](https://github.com/electron-userland/electron-builder/wiki/Options#AppMetadata).
    *
@@ -60,6 +65,8 @@ export interface BuildInfo {
 
   devMetadata: DevMetadata
 
+  config: BuildMetadata
+
   projectDir: string
   appDir: string
   devPackageFile: string
@@ -82,7 +89,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
   readonly projectDir: string
   readonly buildResourcesDir: string
 
-  readonly devMetadata: DevMetadata
+  readonly config: BuildMetadata
 
   readonly platformSpecificBuildOptions: DC
 
@@ -92,9 +99,9 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
 
   readonly appInfo: AppInfo
 
-  constructor(public readonly info: BuildInfo) {
-    this.devMetadata = info.devMetadata
-    this.platformSpecificBuildOptions = this.normalizePlatformSpecificBuildOptions((<any>info.devMetadata.build)[this.platform.buildConfigurationKey])
+  constructor(readonly info: BuildInfo) {
+    this.config = info.config
+    this.platformSpecificBuildOptions = this.normalizePlatformSpecificBuildOptions((<any>this.config)[this.platform.buildConfigurationKey])
     this.appInfo = this.prepareAppInfo(info.appInfo)
     this.options = info.options
     this.projectDir = info.projectDir
@@ -138,7 +145,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
   }
 
   get relativeBuildResourcesDirname() {
-    return use(this.devMetadata.directories, it => it!.buildResources) || "build"
+    return use(getDirectoriesConfig(this.info.devMetadata), it => it!.buildResources) || "build"
   }
 
   protected computeAppOutDir(outDir: string, arch: Arch): string {
@@ -219,7 +226,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
       ".nyc_output}")
 
     let rawFilter: any = null
-    const deprecatedIgnore = (<any>this.devMetadata.build).ignore
+    const deprecatedIgnore = (<any>this.config).ignore
     if (deprecatedIgnore != null) {
       if (typeof deprecatedIgnore === "function") {
         warn(`"ignore" is specified as function, may be new "files" option will be suit your needs? Please see https://github.com/electron-userland/electron-builder/wiki/Options#BuildMetadata-files`)
@@ -274,11 +281,11 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
     await this.doCopyExtraFiles(extraResourceMatchers)
     await this.doCopyExtraFiles(extraFileMatchers)
 
-    const afterPack = this.devMetadata.build.afterPack
+    const afterPack = this.config.afterPack
     if (afterPack != null) {
       await afterPack({
         appOutDir: appOutDir,
-        options: this.devMetadata.build,
+        options: this.config,
         packager: this,
       })
     }
@@ -298,7 +305,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
       return `${name} is deprecated is deprecated and not supported — please use build.asarUnpack`
     }
 
-    const buildMetadata = <any>this.devMetadata.build
+    const buildMetadata = <any>this.config
     if (buildMetadata["asar-unpack"] != null) {
       throw new Error(errorMessage("asar-unpack"))
     }
@@ -307,7 +314,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
     }
 
     const platformSpecific = customBuildOptions.asar
-    const result = platformSpecific == null ? this.devMetadata.build.asar : platformSpecific
+    const result = platformSpecific == null ? this.config.asar : platformSpecific
     if (result === false) {
       warn("Packaging using asar archive is disabled — it is strongly not recommended.\n" +
         "Please enable asar and use asarUnpack to unpack files that must be externally available.")
@@ -344,7 +351,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
   }
 
   private getFileMatchers(name: "files" | "extraFiles" | "extraResources" | "asarUnpack", defaultSrc: string, defaultDest: string, allowAdvancedMatching: boolean, fileMatchOptions: FileMatchOptions, customBuildOptions: DC): Array<FileMatcher> | null {
-    let globalPatterns: Array<string | FilePattern> | string | n | FilePattern = (<any>this.devMetadata.build)[name]
+    let globalPatterns: Array<string | FilePattern> | string | n | FilePattern = (<any>this.config)[name]
     let platformSpecificPatterns: Array<string | FilePattern> | string | n = (<any>customBuildOptions)[name]
 
     const defaultMatcher = new FileMatcher(defaultSrc, defaultDest, fileMatchOptions)
@@ -495,7 +502,7 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
   }
 
   getFileAssociations(): Array<FileAssociation> {
-    return asArray(this.devMetadata.build.fileAssociations).concat(asArray(this.platformSpecificBuildOptions.fileAssociations))
+    return asArray(this.config.fileAssociations).concat(asArray(this.platformSpecificBuildOptions.fileAssociations))
   }
 
   async getResource(custom: string | n, ...names: Array<string>): Promise<string | null> {
@@ -565,7 +572,7 @@ export function getPublishConfigs(packager: PlatformPackager<any>, platformSpeci
   }
 
   if (publishers == null) {
-    publishers = packager.info.devMetadata.build.publish
+    publishers = packager.config.publish
     if (publishers === null) {
       return null
     }
diff --git a/src/repositoryInfo.ts b/src/repositoryInfo.ts
index 3d478e9c7b6..36ec8cb1e6c 100644
--- a/src/repositoryInfo.ts
+++ b/src/repositoryInfo.ts
@@ -1,6 +1,6 @@
 import { fromUrl as parseRepositoryUrl, Info } from "hosted-git-info"
 import { readFile } from "fs-extra-p"
-import { AppMetadata, Metadata } from "./metadata"
+import { AppMetadata, Metadata, RepositoryInfo } from "./metadata"
 import * as path from "path"
 
 export interface RepositorySlug {
@@ -12,7 +12,7 @@ let info: Promise<Info> | null
 
 export function getRepositoryInfo(metadata?: AppMetadata, devMetadata?: Metadata): Promise<Info | null> {
   if (info == null) {
-    info = _getInfo(metadata, devMetadata)
+    info = _getInfo(<RepositoryInfo>(devMetadata == null ? null : devMetadata.repository) || (metadata == null ? null : metadata.repository))
   }
   return info
 }
@@ -45,8 +45,7 @@ async function getGitUrlFromGitConfig(): Promise<string | null> {
   return null
 }
 
-async function _getInfo(metadata?: AppMetadata, devMetadata?: Metadata): Promise<RepositorySlug | null> {
-  const repo = metadata == null ? null : (devMetadata!.repository || metadata!.repository)
+async function _getInfo(repo?: RepositoryInfo | null): Promise<RepositorySlug | null> {
   if (repo == null) {
     let url = process.env.TRAVIS_REPO_SLUG
     if (url == null) {
diff --git a/src/targets/LinuxTargetHelper.ts b/src/targets/LinuxTargetHelper.ts
index e261e155ae9..de78bfa0586 100644
--- a/src/targets/LinuxTargetHelper.ts
+++ b/src/targets/LinuxTargetHelper.ts
@@ -57,7 +57,7 @@ export class LinuxTargetHelper {
   }
 
   private async getIcns(): Promise<string | null> {
-    const build = this.packager.devMetadata.build
+    const build = this.packager.config
     let iconPath = (build.mac || {}).icon || build.icon
     if (iconPath != null && !iconPath.endsWith(".icns")) {
       iconPath += ".icns"
diff --git a/src/targets/appImage.ts b/src/targets/appImage.ts
index ecd2d734e92..cc502539458 100644
--- a/src/targets/appImage.ts
+++ b/src/targets/appImage.ts
@@ -18,7 +18,7 @@ const appImageSha256 = process.platform === "darwin" ? "5d4a954876654403698a01ef
 const appImagePathPromise = getBin("AppImage", appImageVersion, `https://dl.bintray.com/electron-userland/bin/${appImageVersion}.7z`, appImageSha256)
 
 export default class AppImageTarget extends Target {
-  private readonly options = Object.assign({}, this.packager.platformSpecificBuildOptions, (<any>this.packager.devMetadata.build)[this.name])
+  private readonly options = Object.assign({}, this.packager.platformSpecificBuildOptions, (<any>this.packager.config)[this.name])
   private readonly desktopEntry: Promise<string>
 
   constructor(ignored: string, private packager: LinuxPackager, private helper: LinuxTargetHelper, private outDir: string) {
@@ -64,7 +64,7 @@ export default class AppImageTarget extends Target {
     args.push("-map", this.helper.maxIconPath, "/.DirIcon")
 
     args.push("-chown_r", "0", "/", "--")
-    args.push("-zisofs", `level=${packager.devMetadata.build.compression === "store" ? "0" : "9"}:block_size=128k:by_magic=off`)
+    args.push("-zisofs", `level=${packager.config.compression === "store" ? "0" : "9"}:block_size=128k:by_magic=off`)
     args.push("set_filter_r", "--zisofs", "/")
 
     if (this.packager.options.effectiveOptionComputed != null && await this.packager.options.effectiveOptionComputed([args, desktopFile])) {
diff --git a/src/targets/appx.ts b/src/targets/appx.ts
index a37c0e98a41..dadb5a936f7 100644
--- a/src/targets/appx.ts
+++ b/src/targets/appx.ts
@@ -13,7 +13,7 @@ import { release } from "os"
 import { copyDir } from "../util/fs"
 
 export default class AppXTarget extends Target {
-  private readonly options: AppXOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, this.packager.devMetadata.build.appx)
+  private readonly options: AppXOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, this.packager.config.appx)
 
   constructor(private readonly packager: WinPackager, private readonly outDir: string) {
     super("appx")
diff --git a/src/targets/dmg.ts b/src/targets/dmg.ts
index 188474ed5c6..957b24af5d6 100644
--- a/src/targets/dmg.ts
+++ b/src/targets/dmg.ts
@@ -154,7 +154,7 @@ export class DmgTarget extends Target {
 
     const artifactPath = path.join(appOutDir, `${appInfo.productFilename}-${appInfo.version}.dmg`)
     //noinspection SpellCheckingInspection
-    await spawn("hdiutil", addVerboseIfNeed(["convert", tempDmg, "-format", packager.devMetadata.build.compression === "store" ? "UDRO" : "UDBZ", "-imagekey", "zlib-level=9", "-o", artifactPath]))
+    await spawn("hdiutil", addVerboseIfNeed(["convert", tempDmg, "-format", packager.config.compression === "store" ? "UDRO" : "UDBZ", "-imagekey", "zlib-level=9", "-o", artifactPath]))
     await exec("hdiutil", addVerboseIfNeed(["internet-enable", "-no"]).concat(artifactPath))
 
     this.packager.dispatchArtifactCreated(artifactPath, `${appInfo.name}-${appInfo.version}.dmg`)
@@ -180,7 +180,7 @@ export class DmgTarget extends Target {
         x: 400,
         y: 100,
       },
-    }, packager.devMetadata.build.dmg)
+    }, packager.config.dmg)
 
     // appdmg
     const oldPosition = specification.window.position
@@ -241,7 +241,7 @@ export class DmgTarget extends Target {
     }
 
     if (specification.format == null) {
-      specification.format = packager.devMetadata.build.compression === "store" ? "UDRO" : "UDBZ"
+      specification.format = packager.config.compression === "store" ? "UDRO" : "UDBZ"
     }
 
     return specification
diff --git a/src/targets/fpm.ts b/src/targets/fpm.ts
index b4d0b830232..d0962389cd6 100644
--- a/src/targets/fpm.ts
+++ b/src/targets/fpm.ts
@@ -30,7 +30,7 @@ function downloadFpm(): Promise<string> {
 }
 
 export default class FpmTarget extends Target {
-  private readonly options = Object.assign({}, this.packager.platformSpecificBuildOptions, (<any>this.packager.devMetadata.build)[this.name])
+  private readonly options = Object.assign({}, this.packager.platformSpecificBuildOptions, (<any>this.packager.config)[this.name])
 
   private readonly scriptFiles: Promise<Array<string>>
   private readonly desktopEntry: Promise<string>
@@ -114,10 +114,10 @@ export default class FpmTarget extends Target {
     }
 
     if (target === "deb") {
-      args.push("--deb-compression", options.compression || (packager.devMetadata.build.compression === "store" ? "gz" : "xz"))
+      args.push("--deb-compression", options.compression || (packager.config.compression === "store" ? "gz" : "xz"))
     }
     else if (target === "rpm") {
-      // args.push("--rpm-compression", options.compression || (this.devMetadata.build.compression === "store" ? "none" : "xz"))
+      // args.push("--rpm-compression", options.compression || (this.config.compression === "store" ? "none" : "xz"))
       args.push("--rpm-os", "linux")
 
       if (synopsis != null) {
@@ -147,7 +147,7 @@ export default class FpmTarget extends Target {
       args.push("--depends", dep)
     }
 
-    use(packager.appInfo.metadata.license || packager.devMetadata.license, it => args.push("--license", it!))
+    use(packager.appInfo.metadata.license, it => args.push("--license", it!))
     use(appInfo.buildNumber, it => args.push("--iteration", it!))
 
     use(options.fpm, it => args.push(...<any>it))
diff --git a/src/targets/nsis.ts b/src/targets/nsis.ts
index a249be8e10c..4e55d655da7 100644
--- a/src/targets/nsis.ts
+++ b/src/targets/nsis.ts
@@ -25,7 +25,7 @@ const ELECTRON_BUILDER_NS_UUID = "50e065bc-3134-11e6-9bab-38c9862bdaf3"
 const nsisPathPromise = getBinFromBintray("nsis", NSIS_VERSION, NSIS_SHA2)
 
 export default class NsisTarget extends Target {
-  private readonly options: NsisOptions = this.packager.info.devMetadata.build.nsis || Object.create(null)
+  private readonly options: NsisOptions = this.packager.config.nsis || Object.create(null)
 
   private archs: Map<Arch, Promise<string>> = new Map()
 
@@ -67,7 +67,7 @@ export default class NsisTarget extends Target {
 
     const packager = this.packager
     const archiveFile = path.join(this.outDir, `${packager.appInfo.name}-${packager.appInfo.version}-${Arch[arch]}.nsis.7z`)
-    return await archive(packager.devMetadata.build.compression, "7z", archiveFile, appOutDir, true)
+    return await archive(packager.config.compression, "7z", archiveFile, appOutDir, true)
   }
 
   async finishBuild(): Promise<any> {
@@ -164,7 +164,7 @@ export default class NsisTarget extends Target {
       Unicode: true,
     }
 
-    if (packager.devMetadata.build.compression === "store") {
+    if (packager.config.compression === "store") {
       commands.SetCompress = "off"
       defines.COMPRESS = "off"
     }
diff --git a/src/targets/snap.ts b/src/targets/snap.ts
index 944d155fb24..1183564b9cc 100644
--- a/src/targets/snap.ts
+++ b/src/targets/snap.ts
@@ -12,7 +12,7 @@ import { homedir } from "os"
 import { Target } from "./targetFactory"
 
 export default class SnapTarget extends Target {
-  private readonly options: SnapOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, (<any>this.packager.devMetadata.build)[this.name])
+  private readonly options: SnapOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, (<any>this.packager.config)[this.name])
 
   constructor(name: string, private packager: LinuxPackager, private helper: LinuxTargetHelper, private outDir: string) {
     super(name)
diff --git a/src/targets/squirrelWindows.ts b/src/targets/squirrelWindows.ts
index d0e2d6578fb..242750e8264 100644
--- a/src/targets/squirrelWindows.ts
+++ b/src/targets/squirrelWindows.ts
@@ -14,7 +14,7 @@ const SW_VERSION = "1.4.4"
 const SW_SHA2 = "98e1d81c80d7afc1bcfb37f3b224dc4f761088506b9c28ccd72d1cf8752853ba"
 
 export default class SquirrelWindowsTarget extends Target {
-  private readonly options: SquirrelWindowsOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, this.packager.devMetadata.build.squirrelWindows)
+  private readonly options: SquirrelWindowsOptions = Object.assign({}, this.packager.platformSpecificBuildOptions, this.packager.config.squirrelWindows)
 
   constructor(private readonly packager: WinPackager, private readonly outDir: string) {
     super("squirrel")
@@ -51,9 +51,9 @@ export default class SquirrelWindowsTarget extends Target {
 
   async computeEffectiveDistOptions(): Promise<SquirrelOptions> {
     const packager = this.packager
-    let iconUrl = this.options.iconUrl || packager.devMetadata.build.iconUrl
+    let iconUrl = this.options.iconUrl || packager.config.iconUrl
     if (iconUrl == null) {
-      const info = await getRepositoryInfo(packager.appInfo.metadata, packager.devMetadata)
+      const info = await getRepositoryInfo(packager.appInfo.metadata, packager.info.devMetadata)
       if (info != null) {
         iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${packager.relativeBuildResourcesDirname}/icon.ico?raw=true`
       }
@@ -77,7 +77,7 @@ export default class SquirrelWindowsTarget extends Target {
       iconUrl: iconUrl,
       extraMetadataSpecs: projectUrl == null ? null : `\n    <projectUrl>${projectUrl}</projectUrl>`,
       copyright: appInfo.copyright,
-      packageCompressionLevel: packager.devMetadata.build.compression === "store" ? 0 : 9,
+      packageCompressionLevel: packager.config.compression === "store" ? 0 : 9,
       vendorPath: await getBinFromBintray("Squirrel.Windows", SW_VERSION, SW_SHA2)
     }, this.options)
 
@@ -93,7 +93,7 @@ export default class SquirrelWindowsTarget extends Target {
     }
 
     if (options.remoteReleases === true) {
-      const info = await getRepositoryInfo(packager.appInfo.metadata, packager.devMetadata)
+      const info = await getRepositoryInfo(packager.appInfo.metadata, packager.info.devMetadata)
       if (info == null) {
         warn("remoteReleases set to true, but cannot get repository info")
       }
diff --git a/src/targets/targetFactory.ts b/src/targets/targetFactory.ts
index b513e789c51..5e11e2a1078 100644
--- a/src/targets/targetFactory.ts
+++ b/src/targets/targetFactory.ts
@@ -102,10 +102,10 @@ class ArchiveTarget extends Target {
 
     const dirToArchive = isMac ? path.join(appOutDir, `${packager.appInfo.productFilename}.app`) : appOutDir
     if (format.startsWith("tar.")) {
-      await tar(packager.devMetadata.build.compression, format, outFile, dirToArchive, isMac)
+      await tar(packager.config.compression, format, outFile, dirToArchive, isMac)
     }
     else {
-      await archive(packager.devMetadata.build.compression, format, outFile, dirToArchive)
+      await archive(packager.config.compression, format, outFile, dirToArchive)
     }
 
     packager.dispatchArtifactCreated(outFile, isMac ? packager.generateName2(format, "mac", true) : packager.generateName(format, arch, true, packager.platform === Platform.WINDOWS ? "win" : null))
diff --git a/src/util/util.ts b/src/util/util.ts
index 2ee98b2095e..9943a520d44 100644
--- a/src/util/util.ts
+++ b/src/util/util.ts
@@ -9,6 +9,7 @@ import { warn, log } from "./log"
 import { createHash } from "crypto"
 import "source-map-support/register"
 import { statOrNull } from "./fs"
+import { DevMetadata } from "../metadata"
 
 export const debug = _debug("electron-builder")
 export const debug7z = _debug("electron-builder:7z")
@@ -257,4 +258,8 @@ export function getCacheDirectory(): string {
   else {
     return path.join(homedir(), ".cache", "electron-builder")
   }
+}
+
+export function getDirectoriesConfig(m: DevMetadata) {
+  return m.build.directories || (<any>m).directories
 }
\ No newline at end of file
diff --git a/src/winPackager.ts b/src/winPackager.ts
index c232b3b2449..f204e6edff2 100644
--- a/src/winPackager.ts
+++ b/src/winPackager.ts
@@ -104,7 +104,7 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
   }
 
   private async getValidIconPath(): Promise<string | null> {
-    let iconPath = this.platformSpecificBuildOptions.icon || this.devMetadata.build.icon
+    let iconPath = this.platformSpecificBuildOptions.icon || this.config.icon
     if (iconPath != null && !iconPath.endsWith(".ico")) {
       iconPath += ".ico"
     }
@@ -121,6 +121,11 @@ export class WinPackager extends PlatformPackager<WinBuildOptions> {
   async sign(file: string) {
     const cscInfo = await this.cscInfo
     if (cscInfo == null) {
+      const forceCodeSigningPlatform = this.platformSpecificBuildOptions.forceCodeSigning
+      if (forceCodeSigningPlatform == null ? this.config.forceCodeSigning : forceCodeSigningPlatform) {
+        throw new Error(`App is not signed and "forceCodeSigning" is set to true, please ensure that code signing configuration is correct, please see https://github.com/electron-userland/electron-builder/wiki/Code-Signing`)
+      }
+
       return
     }
 
diff --git a/test/fixtures/test-app/package.json b/test/fixtures/test-app/package.json
index 1e2a1678185..c38401959cb 100755
--- a/test/fixtures/test-app/package.json
+++ b/test/fixtures/test-app/package.json
@@ -5,6 +5,7 @@
     "appId": "org.electron-builder.testApp",
     "category": "your.app.category.type",
     "iconUrl": "https://raw.githubusercontent.com/szwacz/electron-boilerplate/master/resources/windows/icon.ico",
-    "compression": "store"
+    "compression": "store",
+    "npmRebuild": false
   }
 }
diff --git a/test/src/ArtifactPublisherTest.ts b/test/src/ArtifactPublisherTest.ts
index 3b64e5e3976..cf5216f9f2f 100644
--- a/test/src/ArtifactPublisherTest.ts
+++ b/test/src/ArtifactPublisherTest.ts
@@ -119,8 +119,6 @@ it("create publisher", async () => {
   const packager: any = {
     metadata: {
       version: "2.0.0",
-    },
-    devMetadata: {
       repository: "develar/test"
     },
   }
diff --git a/test/src/BuildTest.ts b/test/src/BuildTest.ts
index 6e031f4eb74..e2f2928db54 100644
--- a/test/src/BuildTest.ts
+++ b/test/src/BuildTest.ts
@@ -162,18 +162,15 @@ test("afterPack", () => {
   let called = 0
   return assertPack("test-app-one", {
     targets: targets,
-    devMetadata: {
-      build: {
-        afterPack: () => {
-          called++
-          return BluebirdPromise.resolve()
-        }
+    config: {
+      afterPack: () => {
+        called++
+        return BluebirdPromise.resolve()
       }
     }
   }, {
-    packed: () => {
+    packed: async () => {
       expect(called).toEqual(targets.size)
-      return BluebirdPromise.resolve()
     }
   })
 })
diff --git a/test/src/filesTest.ts b/test/src/filesTest.ts
index f3cc26c5eac..9399677802e 100644
--- a/test/src/filesTest.ts
+++ b/test/src/filesTest.ts
@@ -11,11 +11,9 @@ import { Permissions } from "stat-mode"
 
 test.ifDevOrLinuxCi("files", app({
   targets: Platform.LINUX.createTarget(DIR_TARGET),
-  devMetadata: {
-    build: {
-      asar: false,
-      files: ["!ignoreMe${/*}", "!**/bar"],
-    }
+  config: {
+    asar: false,
+    files: ["!ignoreMe${/*}", "!**/bar"],
   }
 }, {
   projectDirCreated: projectDir => BluebirdPromise.all([
@@ -106,10 +104,8 @@ test("extraResources - one-package", () => {
   return assertPack("test-app-one", {
     // to check NuGet package
     targets: platform.createTarget(platform === Platform.WINDOWS ? "squirrel" : DIR_TARGET),
-    devMetadata: {
-      build: {
-        asar: true,
-      },
+    config: {
+      asar: true,
     },
   }, {
     projectDirCreated: projectDir => {
diff --git a/test/src/globTest.ts b/test/src/globTest.ts
index 3440aa2a34c..3af53589f03 100644
--- a/test/src/globTest.ts
+++ b/test/src/globTest.ts
@@ -8,10 +8,8 @@ import { statFile } from "asar-electron-builder"
 
 test.ifDevOrLinuxCi("unpackDir one", app({
   targets: Platform.LINUX.createTarget(DIR_TARGET),
-  devMetadata: {
-    build: {
-      asarUnpack: ["assets", "b2"],
-    }
+  config: {
+    asarUnpack: ["assets", "b2"],
   }
 }, {
   projectDirCreated: projectDir => {
@@ -31,10 +29,8 @@ test.ifDevOrLinuxCi("unpackDir one", app({
 test.ifDevOrLinuxCi("unpackDir", () => {
   return assertPack("test-app", {
     targets: Platform.LINUX.createTarget(DIR_TARGET),
-    devMetadata: {
-      build: {
-        asarUnpack: ["assets", "b2"],
-      }
+    config: {
+      asarUnpack: ["assets", "b2"],
     }
   }, {
     projectDirCreated: projectDir => {
diff --git a/test/src/helpers/packTester.ts b/test/src/helpers/packTester.ts
index 27a3f8f416a..e1e6cc81e02 100755
--- a/test/src/helpers/packTester.ts
+++ b/test/src/helpers/packTester.ts
@@ -77,7 +77,7 @@ export async function assertPack(fixtureName: string, packagerOptions: PackagerO
   }
 
   const projectDirCreated = checkOptions.projectDirCreated
-  const useTempDir = process.env.TEST_APP_TMP_DIR != null || (checkOptions.useTempDir !== false && (checkOptions.useTempDir || projectDirCreated != null || packagerOptions.devMetadata != null || checkOptions.npmInstallBefore))
+  const useTempDir = process.env.TEST_APP_TMP_DIR != null || (checkOptions.useTempDir !== false && (checkOptions.useTempDir || projectDirCreated != null || packagerOptions.config != null || checkOptions.npmInstallBefore))
 
   let projectDir = path.join(__dirname, "..", "..", "fixtures", fixtureName)
   // const isDoNotUseTempDir = platform === "darwin"
@@ -113,11 +113,11 @@ export async function assertPack(fixtureName: string, packagerOptions: PackagerO
     // never output to test fixture app
     if (!useTempDir) {
       dirToDelete = path.join(testDir, `${(tmpDirCounter++).toString(16)}`)
-      const devMetadata = packagerOptions.devMetadata
-      if (devMetadata != null && devMetadata.directories != null) {
+      const config = packagerOptions.config
+      if (config != null && config.directories != null) {
         throw new Error("unsupported")
       }
-      packagerOptions = deepAssign({}, packagerOptions, {devMetadata: {directories: {output: dirToDelete}}})
+      packagerOptions = deepAssign({}, packagerOptions, {config: {directories: {output: dirToDelete}}})
     }
 
     const outDir = useTempDir ? path.join(projectDir, OUT_DIR_NAME) : dirToDelete
@@ -322,7 +322,7 @@ async function checkWindowsResult(packager: Packager, checkOptions: AssertPackOp
   const artifactNames: Array<string> = []
   const expectedFileNames: Array<string> = []
   const archSuffix = getArchSuffix(arch)
-  const buildOptions = packager.devMetadata.build.win
+  const buildOptions = packager.config.win
   for (let target of nameToTarget.keys()) {
     if (target === "squirrel") {
       squirrel = true
@@ -511,11 +511,9 @@ export class CheckingMacPackager extends OsXPackager {
 export function createMacTargetTest(target: Array<MacOsTargetName>, expectedContents: Array<string>) {
   return app({
     targets: Platform.MAC.createTarget(),
-    devMetadata: {
-      build: {
-        mac: {
-          target: target,
-        }
+    config: {
+      mac: {
+        target: target,
       }
     }
   }, {
diff --git a/test/src/ignoreTest.ts b/test/src/ignoreTest.ts
index baae0184c56..02c7add21f3 100644
--- a/test/src/ignoreTest.ts
+++ b/test/src/ignoreTest.ts
@@ -7,10 +7,8 @@ import { Platform, DIR_TARGET } from "out"
 
 test.ifDevOrLinuxCi("ignore build resources", app({
   targets: Platform.LINUX.createTarget(DIR_TARGET),
-  devMetadata: {
-    build: {
-      asar: false
-    }
+  config: {
+    asar: false
   }
 }, {
   projectDirCreated: projectDir => {
@@ -23,10 +21,8 @@ test.ifDevOrLinuxCi("ignore build resources", app({
 
 test.ifDevOrLinuxCi("ignore known ignored files", app({
   targets: Platform.LINUX.createTarget(DIR_TARGET),
-  devMetadata: {
-    build: {
-      asar: false
-    }
+  config: {
+    asar: false
   }
 }, {
   projectDirCreated: projectDir => BluebirdPromise.all([
@@ -48,18 +44,14 @@ test.ifDevOrLinuxCi("ignore known ignored files", app({
 
 // skip on macOS because we want test only / and \
 test.ifNotCiMac("ignore node_modules dev dep", () => {
-  const build: any = {
-    asar: false,
-    ignore: (file: string) => {
-      return file === "/ignoreMe"
-    }
-  }
-
   return assertPack("test-app-one", {
     targets: Platform.LINUX.createTarget(DIR_TARGET),
-    devMetadata: {
-      build: build
-    }
+    config: <any>{
+      asar: false,
+      ignore: (file: string) => {
+        return file === "/ignoreMe"
+      }
+    },
   }, {
     projectDirCreated: projectDir => {
       return BluebirdPromise.all([
diff --git a/test/src/linux/debTest.ts b/test/src/linux/debTest.ts
index 5a20d27f3bc..d10a837949f 100644
--- a/test/src/linux/debTest.ts
+++ b/test/src/linux/debTest.ts
@@ -7,11 +7,9 @@ test.ifNotWindows("arm deb", app({targets: Platform.LINUX.createTarget("deb", Ar
 
 test.ifNotWindows("custom depends", app({
     targets: Platform.LINUX.createTarget("deb"),
-    devMetadata: {
-      build: {
-        deb: {
-          depends: ["foo"],
-        }
+    config: {
+      deb: {
+        depends: ["foo"],
       }
     }
   },
diff --git a/test/src/linux/linuxPackagerTest.ts b/test/src/linux/linuxPackagerTest.ts
index 9bc6ca9ed52..a3a83d688a2 100755
--- a/test/src/linux/linuxPackagerTest.ts
+++ b/test/src/linux/linuxPackagerTest.ts
@@ -15,15 +15,13 @@ test.ifDevOrLinuxCi("AppImage - default icon, custom executable and custom deskt
     expect (content.includes("Terminal=true")).toBeTruthy()
     return false
   },
-  devMetadata: {
-    build: {
-      linux: {
-        executableName: "foo",
-        desktop: {
-          Foo: "bar",
-          Terminal: "true",
-        },
-      }
+  config: {
+    linux: {
+      executableName: "foo",
+      desktop: {
+        Foo: "bar",
+        Terminal: "true",
+      },
     }
   }
 }, {
diff --git a/test/src/mac/dmgTest.ts b/test/src/mac/dmgTest.ts
index 0144a50634d..35dce2a61b9 100644
--- a/test/src/mac/dmgTest.ts
+++ b/test/src/mac/dmgTest.ts
@@ -8,11 +8,9 @@ import { attachAndExecute } from "out/targets/dmg"
 
 test.ifMac("no build directory", app({
   targets: Platform.MAC.createTarget("dmg"),
-  devMetadata: {
-    build: {
-      // dmg can mount only one volume name, so, to test in parallel, we set different product name
-      productName: "NoBuildDirectory",
-    }
+  config: {
+    // dmg can mount only one volume name, so, to test in parallel, we set different product name
+    productName: "NoBuildDirectory",
   }
 }, {
   expectedContents: ["NoBuildDirectory-1.1.0.dmg"],
@@ -49,13 +47,11 @@ test.ifMac("custom background - new way", () => {
 
 test.ifMac("unset dmg icon", app({
   targets: Platform.MAC.createTarget("dmg"),
-  devMetadata: {
-    build: {
-      // dmg can mount only one volume name, so, to test in parallel, we set different product name
-      productName: "Test ß No Volume Icon",
-      dmg: {
-        icon: null,
-      },
+  config: {
+    // dmg can mount only one volume name, so, to test in parallel, we set different product name
+    productName: "Test ß No Volume Icon",
+    dmg: {
+      icon: null,
     }
   }
 }, {
@@ -73,14 +69,12 @@ test.ifMac("unset dmg icon", app({
 // test also "only dmg"
 test.ifMac("no background", app({
   targets: Platform.MAC.createTarget("dmg"),
-  devMetadata: {
-    build: {
-      // dmg can mount only one volume name, so, to test in parallel, we set different product name
-      productName: "NoBackground",
-      dmg: {
-        background: null,
-        title: "Foo",
-      },
+  config: {
+    // dmg can mount only one volume name, so, to test in parallel, we set different product name
+    productName: "NoBackground",
+    dmg: {
+      background: null,
+      title: "Foo",
     }
   }
 }, {
@@ -97,14 +91,12 @@ test.ifMac("disable dmg icon (light), bundleVersion", () => {
   return assertPack("test-app-one", {
     targets: Platform.MAC.createTarget(),
     platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingMacPackager(packager),
-    devMetadata: {
-      build: {
-        dmg: {
-          icon: null,
-        },
-        mac: {
-          bundleVersion: "50"
-        },
+    config: {
+      dmg: {
+        icon: null,
+      },
+      mac: {
+        bundleVersion: "50"
       },
     }
   }, {
diff --git a/test/src/mac/macPackagerTest.ts b/test/src/mac/macPackagerTest.ts
index adee8321e72..975c1f5c1d7 100644
--- a/test/src/mac/macPackagerTest.ts
+++ b/test/src/mac/macPackagerTest.ts
@@ -9,17 +9,15 @@ test.ifMac("two-package", () => assertPack("test-app", {targets: createTargets([
 
 test.ifMac("one-package", app({
   targets: Platform.MAC.createTarget(),
-  devMetadata: {
-    build: {
-      mac: {
-        fileAssociations: [
-          {
-            ext: "foo",
-            name: "Foo",
-            role: "Viewer",
-          },
-        ]
-      }
+  config: {
+    mac: {
+      fileAssociations: [
+        {
+          ext: "foo",
+          name: "Foo",
+          role: "Viewer",
+        },
+      ]
     }
   }
 }, {
diff --git a/test/src/mac/masTest.ts b/test/src/mac/masTest.ts
index cbfa77b664e..002aa8f8738 100644
--- a/test/src/mac/masTest.ts
+++ b/test/src/mac/masTest.ts
@@ -24,15 +24,13 @@ test("custom mas", () => {
   return assertPack("test-app-one", signed({
     targets: Platform.MAC.createTarget(),
     platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingMacPackager(packager),
-    devMetadata: {
-      build: {
-        mac: {
-          target: ["mas"],
-        },
-        mas: {
-          entitlements: "mas-entitlements file path",
-          entitlementsInherit: "mas-entitlementsInherit file path",
-        }
+    config: {
+      mac: {
+        target: ["mas"],
+      },
+      mas: {
+        entitlements: "mas-entitlements file path",
+        entitlementsInherit: "mas-entitlementsInherit file path",
       }
     }
   }), {
@@ -51,12 +49,10 @@ test("entitlements in the package.json", () => {
   return assertPack("test-app-one", signed({
     targets: Platform.MAC.createTarget(),
     platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingMacPackager(packager),
-    devMetadata: {
-      build: {
-        mac: {
-          entitlements: "osx-entitlements file path",
-          entitlementsInherit: "osx-entitlementsInherit file path",
-        }
+    config: {
+      mac: {
+        entitlements: "osx-entitlements file path",
+        entitlementsInherit: "osx-entitlementsInherit file path",
       }
     }
   }), {
diff --git a/test/src/windows/nsisBoring.ts b/test/src/windows/nsisBoring.ts
index ebe48a07418..b78f8d56b80 100644
--- a/test/src/windows/nsisBoring.ts
+++ b/test/src/windows/nsisBoring.ts
@@ -8,14 +8,12 @@ test.ifNotCiMac("boring, MUI_HEADER", () => {
   let installerHeaderPath: string | null = null
   return assertPack("test-app-one", {
       targets: nsisTarget,
-      devMetadata: {
-        build: {
-          nsis: {
-            oneClick: false,
-          }
+      config: {
+        nsis: {
+          oneClick: false,
         }
       },
-      effectiveOptionComputed: async (it) => {
+      effectiveOptionComputed: async(it) => {
         const defines = it[0]
         expect(defines.MUI_HEADERIMAGE).toBeNull()
         expect(defines.MUI_HEADERIMAGE_BITMAP).toEqual(installerHeaderPath)
@@ -35,15 +33,13 @@ test.ifNotCiMac("boring, MUI_HEADER", () => {
 test.ifNotCiMac("boring, MUI_HEADER as option", () => {
   let installerHeaderPath: string | null = null
   return assertPack("test-app-one", {
-      targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32, Arch.x64),
-      devMetadata: {
-        build: {
-          nsis: {
-            oneClick: false,
-            installerHeader: "foo.bmp"
-          }
-        }
-      },
+    targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32, Arch.x64),
+    config: {
+      nsis: {
+        oneClick: false,
+        installerHeader: "foo.bmp"
+      }
+    },
       effectiveOptionComputed: async (it) => {
         const defines = it[0]
         expect(defines.MUI_HEADERIMAGE).toBeNull()
@@ -63,28 +59,24 @@ test.ifNotCiMac("boring, MUI_HEADER as option", () => {
 
 test.ifNotCiMac("boring, only perMachine", app({
   targets: nsisTarget,
-  devMetadata: {
-    build: {
-      nsis: {
-        oneClick: false,
-        perMachine: true,
-      }
+  config: {
+    nsis: {
+      oneClick: false,
+      perMachine: true,
     }
   }
 }))
 
 test.ifNotCiMac("boring", app({
   targets: nsisTarget,
-  devMetadata: {
-    build: {
-      nsis: {
-        oneClick: false,
-        language: "1031",
-      },
-      win: {
-        legalTrademarks: "My Trademark"
-      },
-    }
+  config: {
+    nsis: {
+      oneClick: false,
+      language: "1031",
+    },
+    win: {
+      legalTrademarks: "My Trademark"
+    },
   }
 }, {
   signed: true,
diff --git a/test/src/windows/nsisTest.ts b/test/src/windows/nsisTest.ts
index 24c08083b01..cca6cdc77ba 100644
--- a/test/src/windows/nsisTest.ts
+++ b/test/src/windows/nsisTest.ts
@@ -14,16 +14,14 @@ const nsisTarget = Platform.WINDOWS.createTarget(["nsis"])
 
 test("one-click", app({
   targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32),
-  devMetadata: {
-    build: {
-      publish: {
-        provider: "bintray",
-        owner: "actperepo",
-        package: "TestApp",
-      },
-      // wine creates incorrect filenames and registry entries for unicode, so, we use ASCII
-      // productName: "TestApp",
-    }
+  config: {
+    publish: {
+      provider: "bintray",
+      owner: "actperepo",
+      package: "TestApp",
+    },
+    // wine creates incorrect filenames and registry entries for unicode, so, we use ASCII
+    // productName: "TestApp",
   }
 }, {
   useTempDir: true,
@@ -41,25 +39,23 @@ test("one-click", app({
 
 test.ifDevOrLinuxCi("perMachine, no run after finish", app({
   targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32),
-  devMetadata: {
-    build: {
-      // wine creates incorrect filenames and registry entries for unicode, so, we use ASCII
-      productName: "TestApp",
-      fileAssociations: [
-        {
-          ext: "foo",
-          name: "Test Foo",
-        }
-      ],
-      nsis: {
-        perMachine: true,
-        runAfterFinish: false,
-      },
-      publish: {
-        provider: "generic",
-        url: "https://develar.s3.amazonaws.com/test",
-      },
-    }
+  config: {
+    // wine creates incorrect filenames and registry entries for unicode, so, we use ASCII
+    productName: "TestApp",
+    fileAssociations: [
+      {
+        ext: "foo",
+        name: "Test Foo",
+      }
+    ],
+    nsis: {
+      perMachine: true,
+      runAfterFinish: false,
+    },
+    publish: {
+      provider: "generic",
+      url: "https://develar.s3.amazonaws.com/test",
+    },
   },
 }, {
   projectDirCreated: projectDir => {
diff --git a/test/src/windows/squirrelWindowsTest.ts b/test/src/windows/squirrelWindowsTest.ts
index b810962b957..72fc15a3897 100644
--- a/test/src/windows/squirrelWindowsTest.ts
+++ b/test/src/windows/squirrelWindowsTest.ts
@@ -8,12 +8,10 @@ test.ifNotCiMac("Squirrel.Windows", app({targets: Platform.WINDOWS.createTarget(
 // very slow
 test.skip("delta and msi", app({
   targets: Platform.WINDOWS.createTarget("squirrel", Arch.ia32),
-  devMetadata: {
-    build: {
-      squirrelWindows: {
-        remoteReleases: "https://github.com/develar/__test-app-releases",
-        msi: true,
-      },
+  config: {
+    squirrelWindows: {
+      remoteReleases: "https://github.com/develar/__test-app-releases",
+      msi: true,
     }
   },
 }))
@@ -33,11 +31,9 @@ test("detect install-spinner, certificateFile/password", () => {
   return assertPack("test-app-one", {
     targets: Platform.WINDOWS.createTarget("squirrel"),
     platformPackagerFactory: (packager, platform, cleanupTasks) => platformPackager = new CheckingWinPackager(packager),
-    devMetadata: {
-      build: {
-        win: {
-          certificatePassword: "pass",
-        }
+    config: {
+      win: {
+        certificatePassword: "pass",
       }
     }
   }, {
diff --git a/test/src/windows/winPackagerTest.ts b/test/src/windows/winPackagerTest.ts
index 8d33acb98df..3320baf0b05 100755
--- a/test/src/windows/winPackagerTest.ts
+++ b/test/src/windows/winPackagerTest.ts
@@ -6,7 +6,7 @@ import BluebirdPromise from "bluebird-lst-c"
 
 test.ifDevOrWinCi("beta version", app({
   targets: Platform.WINDOWS.createTarget(["squirrel", "nsis"]),
-  devMetadata: <any>{
+  appMetadata: <any>{
     version: "3.0.0-beta.2",
   }
 }))
@@ -46,11 +46,16 @@ test.ifMac("custom icon", () => {
 
 it.ifDevOrLinuxCi("ev", appThrows(/certificateSubjectName supported only on Windows/, {
   targets: Platform.WINDOWS.createTarget(["dir"]),
-  devMetadata: {
-    build: {
-      win: {
-        certificateSubjectName: "ev",
-      }
+  config: {
+    win: {
+      certificateSubjectName: "ev",
     }
   }
+}))
+
+it.ifDevOrLinuxCi("forceCodeSigning", appThrows(/App is not signed and "forceCodeSigning"/, {
+  targets: Platform.WINDOWS.createTarget(["dir"]),
+  config: {
+    forceCodeSigning: true,
+  }
 }))
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 51630f3d05b..d120df131fa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3357,8 +3357,8 @@ supports-color@^3.1.0, supports-color@^3.1.2:
     has-flag "^1.0.0"
 
 "symbol-tree@>= 3.1.0 < 4.0.0":
-  version "3.1.4"
-  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.1.4.tgz#02b279348d337debc39694c5c95f882d448a312a"
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.0.tgz#2183fcd165fc30048b3421aad29ada7a339ea566"
 
 tar-stream@^1.5.0:
   version "1.5.2"