Repository: serverless/serverless (JavaScript) — Feature

Issue:
Config should also be read from serverless.config.js file.
# This is a Bug Report

## Description

* What went wrong?
When using a js config file (serverless.js) "npx serverless" opens this file in my editor instead of running the serverless executable.
I guess this is why for example webpack uses webpack.config.js by default as the name of config files.
* What did you expect should have happened?
npx serverless should run the executable no matter if you use a yml or json or js config.
I think the js-type config file should be read both from serverless.js for backward compatibility and serverless.config.js to avoid this issue.
* What was the config you used?
Doesn't matter as long as your config file is js.
* What stacktrace or error message from your provider did you see?
N/A

## Additional Data

* ***Serverless Framework Version you're using***:
1.37.1
* ***Operating System***:
Windows 10


Discussion:
That's an unfortunate conflict! I've tagged this as being closed by #5589 which will allow you to use any config file name you like 🙂 
is there any update on when #5589 will be merged in? looks like there is one review comment blocker, other than that is there anything remaining?
I've been trying to fix up that PR myself, but have run into all sorts of weird testing issues. Hopefully I'll be able to wrap up that feature soon once I figure out what's going on with the tests

Resolving patch:
diff --git a/docs/providers/aws/cli-reference/deploy.md b/docs/providers/aws/cli-reference/deploy.md
index 305a5d1cb01..058f6ed4ca3 100644
--- a/docs/providers/aws/cli-reference/deploy.md
+++ b/docs/providers/aws/cli-reference/deploy.md
@@ -19,6 +19,7 @@ serverless deploy
 ```
 
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--stage` or `-s` The stage in your service that you want to deploy to.
 - `--region` or `-r` The region in that stage that you want to deploy to.
 - `--package` or `-p` path to a pre-packaged directory and skip packaging step.
diff --git a/docs/providers/aws/guide/deploying.md b/docs/providers/aws/guide/deploying.md
index 8fd9423cbb7..30a4d5191bd 100644
--- a/docs/providers/aws/guide/deploying.md
+++ b/docs/providers/aws/guide/deploying.md
@@ -24,7 +24,7 @@ serverless deploy
 
 Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to Amazon Web Services.
 
-**Note:** You can always enforce a deployment using the `--force` option.
+**Note:** You can always enforce a deployment using the `--force` option, or specify a different configuration file name with the the `--config` option. 
 
 ### How It Works
 
diff --git a/docs/providers/azure/cli-reference/deploy.md b/docs/providers/azure/cli-reference/deploy.md
index bf53ce438ad..3c22664627c 100644
--- a/docs/providers/azure/cli-reference/deploy.md
+++ b/docs/providers/azure/cli-reference/deploy.md
@@ -23,6 +23,7 @@ serverless deploy
 ```
 
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--noDeploy` or `-n` Skips the deployment steps and leaves artifacts in the `.serverless` directory
 - `--verbose` or `-v` Shows all stack events during deployment, and display any Stack Output.
 - `--function` or `-f` Invoke `deploy function` (see above). Convenience shortcut.
diff --git a/docs/providers/azure/guide/deploying.md b/docs/providers/azure/guide/deploying.md
index a2a97905424..0189364cf1b 100644
--- a/docs/providers/azure/guide/deploying.md
+++ b/docs/providers/azure/guide/deploying.md
@@ -28,6 +28,8 @@ Use this method when you have updated your Function, Event or Resource
 configuration in `serverless.yml` and you want to deploy that change (or multiple
 changes at the same time) to Azure Functions.
 
+**Note:** You can specify a different configuration file name with the the `--config` option. 
+
 ### How It Works
 
 The Serverless Framework translates all syntax in `serverless.yml` to an Azure
diff --git a/docs/providers/azure/guide/intro.md b/docs/providers/azure/guide/intro.md
index f33a846c772..685157c13fa 100644
--- a/docs/providers/azure/guide/intro.md
+++ b/docs/providers/azure/guide/intro.md
@@ -63,7 +63,7 @@ needed for that event and configure your functions to listen to it.
 A **Service** is the Framework's unit of organization. You can think of it as a
 project file, though you can have multiple services for a single application.
 It's where you define your Functions, the Events that trigger them, and the
-Resources your Functions use, all in one file entitled `serverless.yml` (or
+Resources your Functions use, all in one file by default entitled `serverless.yml` (or
 `serverless.json` or `serverless.js`). It looks like this:
 
 ```yml
@@ -91,7 +91,7 @@ functions: # Your "Functions"
 ```
 
 When you deploy with the Framework by running `serverless deploy`, everything in
-`serverless.yml` is deployed at once.
+`serverless.yml` (or the file specified with the `--config` option) is deployed at once.
 
 ### Plugins
 
diff --git a/docs/providers/cloudflare/cli-reference/deploy.md b/docs/providers/cloudflare/cli-reference/deploy.md
index 6e9c3e5fbe4..46d185bef31 100644
--- a/docs/providers/cloudflare/cli-reference/deploy.md
+++ b/docs/providers/cloudflare/cli-reference/deploy.md
@@ -42,6 +42,7 @@ serverless deploy
 This is the simplest deployment usage possible. With this command, Serverless will deploy your service to Cloudflare.
  
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--verbose` or `-v`: Shows all stack events during deployment, and display any Stack Output.
 - `--function` or `-f`: Invokes `deploy function` (see above). Convenience shortcut
 
diff --git a/docs/providers/cloudflare/guide/deploying.md b/docs/providers/cloudflare/guide/deploying.md
index 20c229ee03f..f0e528c6dd2 100644
--- a/docs/providers/cloudflare/guide/deploying.md
+++ b/docs/providers/cloudflare/guide/deploying.md
@@ -45,7 +45,9 @@ serverless deploy
 ```
 
 Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to your Cloudflare Worker. If you've made changes to any of your routes since last deploying, the Serverless Framework will update them on the server for you.
- 
+
+**Note:** You can specify a different configuration file name with the the `--config` option. 
+
 ### How It Works
 The Serverless Framework reads in `serverless.yml` and uses it to provision your Functions.
  
diff --git a/docs/providers/fn/cli-reference/deploy.md b/docs/providers/fn/cli-reference/deploy.md
index 1e1f632c6a8..43efd9c3a18 100644
--- a/docs/providers/fn/cli-reference/deploy.md
+++ b/docs/providers/fn/cli-reference/deploy.md
@@ -23,6 +23,7 @@ serverless deploy
 This is the simplest deployment usage possible. With this command Serverless will deploy your service to the configured Fn server.
 
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--verbose` or `-v` Shows all stack events during deployment, and display any Stack Output.
 - `--function` or `-f` Invoke `deploy function` (see above). Convenience shortcut
 
diff --git a/docs/providers/fn/guide/deploying.md b/docs/providers/fn/guide/deploying.md
index 40463c8540e..45ba7129057 100644
--- a/docs/providers/fn/guide/deploying.md
+++ b/docs/providers/fn/guide/deploying.md
@@ -24,6 +24,8 @@ serverless deploy
 
 Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to your Fn cluster.
 
+**Note:** You can specify a different configuration file name with the the `--config` option. 
+
 ### How It Works
 
 The Serverless Framework translates all syntax in `serverless.yml` to [Fn](https://github.com/fnproject/fn) calls to provision your Functions.
diff --git a/docs/providers/fn/guide/intro.md b/docs/providers/fn/guide/intro.md
index a18a032c52c..b9581a7168c 100644
--- a/docs/providers/fn/guide/intro.md
+++ b/docs/providers/fn/guide/intro.md
@@ -42,7 +42,7 @@ Anything that triggers an Fn Event to execute is regarded by the Framework as an
 
 ### Services
 
-A **Service** is the Serverless Framework's unit of organization.  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions and the Events that trigger them, all in one file entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
+A **Service** is the Serverless Framework's unit of organization.  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions and the Events that trigger them, all in one file by default entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
 
 ```yml
 # serverless.yml
@@ -59,4 +59,4 @@ functions: # Your "Functions"
             path: /hello
 ```
 
-When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once.
+When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` (or the file specified with the `--config` option) is deployed at once.
diff --git a/docs/providers/google/cli-reference/deploy.md b/docs/providers/google/cli-reference/deploy.md
index 0eea151a790..7cc741b4442 100644
--- a/docs/providers/google/cli-reference/deploy.md
+++ b/docs/providers/google/cli-reference/deploy.md
@@ -18,6 +18,9 @@ The `serverless deploy` command deploys your entire service via the Google Cloud
 serverless deploy
 ```
 
+## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
+
 ## Artifacts
 
 After the `serverless deploy` command runs all created deployment artifacts are placed in the `.serverless` folder of the service.
diff --git a/docs/providers/google/guide/deploying.md b/docs/providers/google/guide/deploying.md
index c7faeda3282..5542a4acf7c 100644
--- a/docs/providers/google/guide/deploying.md
+++ b/docs/providers/google/guide/deploying.md
@@ -24,6 +24,8 @@ serverless deploy
 
 Use this method when you have updated your Function, Events or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to the Google Cloud.
 
+**Note:** You can specify a different configuration file name with the the `--config` option. 
+
 ### How It Works
 
 The Serverless Framework translates all syntax in `serverless.yml` to a Google Deployment Manager configuration template.
diff --git a/docs/providers/google/guide/intro.md b/docs/providers/google/guide/intro.md
index 6f03ea68423..d044ae36a7b 100644
--- a/docs/providers/google/guide/intro.md
+++ b/docs/providers/google/guide/intro.md
@@ -46,7 +46,7 @@ When you define an event for your Google Cloud Function in the Serverless Framew
 
 ### Services
 
-A **Service** is the Framework's unit of organization. You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file entitled `serverless.yml` (or `serverless.json` or `serverless.js`). It looks like this:
+A **Service** is the Framework's unit of organization. You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file by default entitled `serverless.yml` (or `serverless.json` or `serverless.js`). It looks like this:
 
 ```yml
 # serverless.yml
@@ -59,7 +59,7 @@ functions: # Your "Functions"
       - http: create
 ```
 
-When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once.
+When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` (or the file specified with the `--config` option) is deployed at once.
 
 ### Plugins
 
diff --git a/docs/providers/kubeless/cli-reference/deploy.md b/docs/providers/kubeless/cli-reference/deploy.md
index dbfa1232d32..b4898ffc40d 100644
--- a/docs/providers/kubeless/cli-reference/deploy.md
+++ b/docs/providers/kubeless/cli-reference/deploy.md
@@ -23,6 +23,7 @@ serverless deploy
 This is the simplest deployment usage possible. With this command Serverless will deploy your service to the default Kubernetes cluster in your kubeconfig file.
 
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--noDeploy` or `-n` Skips the deployment steps and leaves artifacts in the `.serverless` directory.
 - `--verbose` or `-v` Shows all stack events during deployment, and display any Stack Output.
 - `--package` or `-p` The path of a previously packaged deployment to get deployed (skips packaging step).
diff --git a/docs/providers/kubeless/guide/deploying.md b/docs/providers/kubeless/guide/deploying.md
index cdb4883d9ef..7780ad2b66c 100644
--- a/docs/providers/kubeless/guide/deploying.md
+++ b/docs/providers/kubeless/guide/deploying.md
@@ -24,6 +24,8 @@ serverless deploy -v
 
 Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to your Kubernetes cluster.
 
+**Note:** You can specify a different configuration file name with the the `--config` option. 
+
 ### How It Works
 
 The Serverless Framework translates all syntax in `serverless.yml` to [the Function object API](https://github.com/kubeless/kubeless/blob/master/pkg/spec/spec.go) calls to provision your Functions and Events.
diff --git a/docs/providers/kubeless/guide/intro.md b/docs/providers/kubeless/guide/intro.md
index 4a2fdd53354..c056a2f6a56 100644
--- a/docs/providers/kubeless/guide/intro.md
+++ b/docs/providers/kubeless/guide/intro.md
@@ -42,7 +42,7 @@ Anything that triggers an Kubeless Event to execute is regarded by the Framework
 
 ### Services
 
-A **Service** is the Serverless Framework's unit of organization (not to be confused with [Kubernetes Services](https://kubernetes.io/docs/concepts/services-networking/service/).  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions and the Events that trigger them, all in one file entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
+A **Service** is the Serverless Framework's unit of organization (not to be confused with [Kubernetes Services](https://kubernetes.io/docs/concepts/services-networking/service/).  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions and the Events that trigger them, all in one file by default entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
 
 ```yml
 # serverless.yml
@@ -57,4 +57,4 @@ functions: # Your "Functions"
           path: /hello
 ```
 
-When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once.
+When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` (or the file specified with the `--config` option) is deployed at once.
diff --git a/docs/providers/openwhisk/cli-reference/deploy.md b/docs/providers/openwhisk/cli-reference/deploy.md
index 6adb35ee966..52be99c56bf 100644
--- a/docs/providers/openwhisk/cli-reference/deploy.md
+++ b/docs/providers/openwhisk/cli-reference/deploy.md
@@ -19,6 +19,7 @@ serverless deploy
 ```
 
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--noDeploy` or `-n` Skips the deployment steps and leaves artifacts in the `.serverless` directory
 - `--verbose` or `-v` Shows all stack events during deployment, and display any Stack Output.
 - `--function` or `-f` Invoke `deploy function` (see above). Convenience shortcut - cannot be used with `--package`.
diff --git a/docs/providers/openwhisk/guide/deploying.md b/docs/providers/openwhisk/guide/deploying.md
index 3236e3c88ee..d403c679e21 100644
--- a/docs/providers/openwhisk/guide/deploying.md
+++ b/docs/providers/openwhisk/guide/deploying.md
@@ -24,6 +24,8 @@ serverless deploy
 
 Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to Apache OpenWhisk.
 
+**Note:** You can specify a different configuration file name with the the `--config` option. 
+
 ### How It Works
 
 The Serverless Framework translates all syntax in `serverless.yml` to [platform API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/openwhisk/openwhisk/master/core/controller/src/main/resources/whiskswagger.json) calls to provision your Actions, Triggers, Rules and APIs.
diff --git a/docs/providers/openwhisk/guide/intro.md b/docs/providers/openwhisk/guide/intro.md
index 06738f35bd4..c37b6e3f6c6 100644
--- a/docs/providers/openwhisk/guide/intro.md
+++ b/docs/providers/openwhisk/guide/intro.md
@@ -47,7 +47,7 @@ When you define an event for your Apache OpenWhisk Action in the Serverless Fram
 
 ### Services
 
-A **Service** is the Framework's unit of organization.  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
+A **Service** is the Framework's unit of organization.  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file by default entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
 
 ```yml
 # serverless.yml
@@ -62,7 +62,7 @@ functions: # Your "Functions"
     events:
       - http: delete /users/delete
 ```
-When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once.
+When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` (or the file specified with the `--config` option) is deployed at once.
 
 ### Plugins
 
diff --git a/docs/providers/spotinst/cli-reference/deploy.md b/docs/providers/spotinst/cli-reference/deploy.md
index b5b909220d0..3f5f98d363b 100755
--- a/docs/providers/spotinst/cli-reference/deploy.md
+++ b/docs/providers/spotinst/cli-reference/deploy.md
@@ -19,5 +19,6 @@ serverless deploy -v
 ```
 
 ## Options
+- `--config` or `-c` Path to your conifguration file, if other than `serverless.yml|.yaml|.js|.json`.
 - `--package` or `-p` path to a pre-packaged directory and skip packaging step.
 - `--verbose` or `-v` Shows all stack events during deployment, and display any Stack Output.
diff --git a/docs/providers/spotinst/guide/intro.md b/docs/providers/spotinst/guide/intro.md
index c5b13e15f33..7c8b748b282 100644
--- a/docs/providers/spotinst/guide/intro.md
+++ b/docs/providers/spotinst/guide/intro.md
@@ -73,7 +73,7 @@ module.exports.main = function main (event, context, callback) {
 
 ### Services
 
-A **Service** is the Framework's unit of organization.  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
+A **Service** is the Framework's unit of organization.  You can think of it as a project file, though you can have multiple services for a single application.  It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file by default entitled `serverless.yml` (or `serverless.json` or `serverless.js`).  It looks like this:
 
 ```yml
 
@@ -98,7 +98,7 @@ functions:
 #      key: value
 
 ```
-When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once.
+When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` (or the file specified with the `--config` option) is deployed at once.
 
 ### Plugins
 
diff --git a/lib/Serverless.js b/lib/Serverless.js
index 697c510656e..ca3ffd90b5f 100644
--- a/lib/Serverless.js
+++ b/lib/Serverless.js
@@ -4,6 +4,7 @@ const path = require('path');
 const BbPromise = require('bluebird');
 const os = require('os');
 const updateNotifier = require('update-notifier');
+const minimist = require('minimist');
 const pkg = require('../package.json');
 const CLI = require('./classes/CLI');
 const Config = require('./classes/Config');
@@ -31,7 +32,8 @@ class Serverless {
     this.pluginManager = new PluginManager(this);
 
     // use the servicePath from the options or try to find it in the CWD
-    configObject.servicePath = configObject.servicePath || this.utils.findServicePath();
+    configObject.servicePath = configObject.servicePath ||
+      this.utils.findServicePath(minimist(process.argv.slice(2)).config);
 
     this.config = new Config(this, configObject);
 
diff --git a/lib/classes/CLI.js b/lib/classes/CLI.js
index 4b6b58a7250..53c53f69981 100644
--- a/lib/classes/CLI.js
+++ b/lib/classes/CLI.js
@@ -152,7 +152,16 @@ class CLI {
 
   displayCommandOptions(commandObject) {
     const dotsLength = 40;
-    _.forEach(commandObject.options, (optionsObject, option) => {
+
+    const commandOptions = commandObject.configDependent ?
+      Object.assign({}, commandObject.options, {
+        config: {
+          usage: 'Path to serverless config file',
+          shortcut: 'c',
+        },
+      }) : commandObject.options;
+
+    _.forEach(commandOptions, (optionsObject, option) => {
       let optionsDots = _.repeat('.', dotsLength - option.length);
       const optionsUsage = optionsObject.usage;
 
diff --git a/lib/classes/PluginManager.js b/lib/classes/PluginManager.js
index daf7260e3d3..1e6c063b14b 100644
--- a/lib/classes/PluginManager.js
+++ b/lib/classes/PluginManager.js
@@ -45,7 +45,7 @@ class PluginManager {
 
   loadConfigFile() {
     return serverlessConfigFileUtils
-      .getServerlessConfigFile(this.serverless.config.servicePath)
+      .getServerlessConfigFile(this.serverless)
       .then((serverlessConfigFile) => {
         this.serverlessConfigFile = serverlessConfigFile;
         return;
diff --git a/lib/classes/Service.js b/lib/classes/Service.js
index 0ec8d06062c..74bbd61583a 100644
--- a/lib/classes/Service.js
+++ b/lib/classes/Service.js
@@ -5,6 +5,7 @@ const path = require('path');
 const _ = require('lodash');
 const BbPromise = require('bluebird');
 const semver = require('semver');
+const serverlessConfigFileUtils = require('../utils/getServerlessConfigFile');
 
 const validAPIGatewayStageNamePattern = /^[-_a-zA-Z0-9]+$/;
 
@@ -46,54 +47,17 @@ class Service {
       return BbPromise.resolve();
     }
 
-    // List of supported service filename variants.
-    // The order defines the precedence.
-    const serviceFilenames = [
-      'serverless.yaml',
-      'serverless.yml',
-      'serverless.json',
-      'serverless.js',
-    ];
-
-    const serviceFilePaths = _.map(serviceFilenames, filename => path.join(servicePath, filename));
-    const serviceFileIndex = _.findIndex(serviceFilePaths,
-      filename => this.serverless.utils.fileExistsSync(filename)
-    );
-
-    // Set the filename if found, otherwise set the preferred variant.
-    const serviceFilePath = serviceFileIndex !== -1 ?
-      serviceFilePaths[serviceFileIndex] :
-      _.first(serviceFilePaths);
-    const serviceFilename = serviceFileIndex !== -1 ?
-      serviceFilenames[serviceFileIndex] :
-      _.first(serviceFilenames);
-
-    if (serviceFilename === 'serverless.js') {
-      return BbPromise.try(() => {
-        // use require to load serverless.js file
-        // eslint-disable-next-line global-require
-        const configExport = require(serviceFilePath);
-        // In case of a promise result, first resolve it.
-        return configExport;
-      }).then(config => {
-        if (!_.isPlainObject(config)) {
-          throw new Error('serverless.js must export plain object');
-        }
-
-        return that.loadServiceFileParam(serviceFilename, config);
-      });
-    }
-
-    return that.serverless.yamlParser
-      .parse(serviceFilePath)
-      .then((serverlessFileParam) =>
-        that.loadServiceFileParam(serviceFilename, serverlessFileParam)
-      );
+    return BbPromise.all([
+      serverlessConfigFileUtils.getServerlessConfigFilePath(this.serverless),
+      serverlessConfigFileUtils.getServerlessConfigFile(this.serverless),
+    ]).then((args) => that.loadServiceFileParam(...args));
   }
 
   loadServiceFileParam(serviceFilename, serverlessFileParam) {
     const that = this;
 
+    that.serviceFilename = path.basename(serviceFilename);
+
     const serverlessFile = serverlessFileParam;
     // basic service level validation
     const version = this.serverless.utils.getVersion();
@@ -101,18 +65,18 @@ class Service {
     if (ymlVersion && !semver.satisfies(version, ymlVersion)) {
       const errorMessage = [
         `The Serverless version (${version}) does not satisfy the`,
-        ` "frameworkVersion" (${ymlVersion}) in ${serviceFilename}`,
+        ` "frameworkVersion" (${ymlVersion}) in ${this.serviceFilename}`,
       ].join('');
       throw new ServerlessError(errorMessage);
     }
     if (!serverlessFile.service) {
-      throw new ServerlessError(`"service" property is missing in ${serviceFilename}`);
+      throw new ServerlessError(`"service" property is missing in ${this.serviceFilename}`);
     }
     if (_.isObject(serverlessFile.service) && !serverlessFile.service.name) {
-      throw new ServerlessError(`"service" is missing the "name" property in ${serviceFilename}`);   // eslint-disable-line max-len
+      throw new ServerlessError(`"service" is missing the "name" property in ${this.serviceFilename}`);   // eslint-disable-line max-len
     }
     if (!serverlessFile.provider) {
-      throw new ServerlessError(`"provider" property is missing in ${serviceFilename}`);
+      throw new ServerlessError(`"provider" property is missing in ${this.serviceFilename}`);
     }
 
     // #######################################################################
diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js
index c55adb24f25..793e46e432e 100644
--- a/lib/classes/Utils.js
+++ b/lib/classes/Utils.js
@@ -106,10 +106,16 @@ class Utils {
     return Math.random().toString(36).substr(2, length);
   }
 
-  findServicePath() {
+  findServicePath(customPath) {
     let servicePath = null;
 
-    if (fileExistsSync(path.join(process.cwd(), 'serverless.yml'))) {
+    if (customPath) {
+      if (fileExistsSync(path.join(process.cwd(), customPath))) {
+        servicePath = process.cwd();
+      } else {
+        throw new Error(`Config file ${customPath} not found`);
+      }
+    } else if (fileExistsSync(path.join(process.cwd(), 'serverless.yml'))) {
       servicePath = process.cwd();
     } else if (fileExistsSync(path.join(process.cwd(), 'serverless.yaml'))) {
       servicePath = process.cwd();
diff --git a/lib/plugins/package/lib/packageService.js b/lib/plugins/package/lib/packageService.js
index 2ba7159e22e..ab6d27a82ed 100644
--- a/lib/plugins/package/lib/packageService.js
+++ b/lib/plugins/package/lib/packageService.js
@@ -24,7 +24,7 @@ module.exports = {
 
   getExcludes(exclude, excludeLayers) {
     return serverlessConfigFileUtils
-      .getServerlessConfigFilePath(this.serverless.config.servicePath)
+      .getServerlessConfigFilePath(this.serverless)
       .then(configFilePath => {
         const packageExcludes = this.serverless.service.package.exclude || [];
         // add local service plugins Path
diff --git a/lib/plugins/print/print.js b/lib/plugins/print/print.js
index aea70be26e8..d0dcffb3204 100644
--- a/lib/plugins/print/print.js
+++ b/lib/plugins/print/print.js
@@ -96,7 +96,7 @@ class Print {
     // the codebase.  Avoiding that, this method must read the serverless.yml file itself, adorn it
     // as the Service class would and then populate it, reversing the adornments thereafter in
     // preparation for printing the service for the user.
-    return getServerlessConfigFile(this.serverless.config.servicePath)
+    return getServerlessConfigFile(this.serverless)
       .then((svc) => {
         const service = svc;
         this.adorn(service);
diff --git a/lib/utils/autocomplete.js b/lib/utils/autocomplete.js
index 84cec0b94f3..5381da6d024 100644
--- a/lib/utils/autocomplete.js
+++ b/lib/utils/autocomplete.js
@@ -41,7 +41,7 @@ const cacheFileValid = (serverlessConfigFile, validationHash) => {
 
 const autocomplete = () => {
   const servicePath = process.cwd();
-  return getServerlessConfigFile(servicePath)
+  return getServerlessConfigFile({ processedInput: { options: {} }, config: { servicePath } })
     .then((serverlessConfigFile) => getCacheFile(servicePath)
       .then((cacheFile) => {
         if (!cacheFile || !cacheFileValid(serverlessConfigFile, cacheFile.validationHash)) {
diff --git a/lib/utils/getServerlessConfigFile.js b/lib/utils/getServerlessConfigFile.js
index c0f07a6b2bd..c185b1d1d0d 100644
--- a/lib/utils/getServerlessConfigFile.js
+++ b/lib/utils/getServerlessConfigFile.js
@@ -6,8 +6,14 @@ const path = require('path');
 const fileExists = require('./fs/fileExists');
 const readFile = require('./fs/readFile');
 
-const getServerlessConfigFilePath = (srvcPath) => {
-  const servicePath = srvcPath || process.cwd();
+const getServerlessConfigFilePath = (serverless) => {
+  const servicePath = serverless.config.servicePath || process.cwd();
+
+  if (serverless.processedInput.options.config) {
+    const customPath = path.join(servicePath, serverless.processedInput.options.config);
+    return fileExists(customPath).then(exists => (exists ? customPath : null));
+  }
+
   const jsonPath = path.join(servicePath, 'serverless.json');
   const ymlPath = path.join(servicePath, 'serverless.yml');
   const yamlPath = path.join(servicePath, 'serverless.yaml');
@@ -19,12 +25,12 @@ const getServerlessConfigFilePath = (srvcPath) => {
     yaml: fileExists(yamlPath),
     js: fileExists(jsPath),
   }).then(exists => {
-    if (exists.json) {
-      return jsonPath;
+    if (exists.yaml) {
+      return yamlPath;
     } else if (exists.yml) {
       return ymlPath;
-    } else if (exists.yaml) {
-      return yamlPath;
+    } else if (exists.json) {
+      return jsonPath;
     } else if (exists.js) {
       return jsPath;
     }
@@ -46,7 +52,8 @@ const handleJsConfigFile = (jsConfigFile) => BbPromise.try(() => {
   throw new Error('serverless.js must export plain object');
 });
 
-const getServerlessConfigFile = _.memoize(srvcPath => getServerlessConfigFilePath(srvcPath)
+const getServerlessConfigFile = _.memoize((serverless) =>
+  getServerlessConfigFilePath(serverless)
   .then(configFilePath => {
     if (configFilePath !== null) {
       const isJSConfigFile = _.last(_.split(configFilePath, '.')) === 'js';
@@ -59,7 +66,8 @@ const getServerlessConfigFile = _.memoize(srvcPath => getServerlessConfigFilePat
     }
 
     return '';
-  })
-);
+  }),
+  (serverless) => `${
+    serverless.processedInput.options.config} - ${serverless.config.servicePath}`);
 
 module.exports = { getServerlessConfigFile, getServerlessConfigFilePath };


Test patch:
diff --git a/lib/classes/Service.test.js b/lib/classes/Service.test.js
index d5342a097f8..d53c23b4d90 100644
--- a/lib/classes/Service.test.js
+++ b/lib/classes/Service.test.js
@@ -17,6 +17,7 @@ const expect = require('chai').expect;
 describe('Service', () => {
   describe('#constructor()', () => {
     const serverless = new Serverless();
+    serverless.processedInput = { options: {} };
 
     it('should attach serverless instance', () => {
       const serviceInstance = new Service(serverless);
@@ -118,6 +119,7 @@ describe('Service', () => {
 
     it('should resolve if no servicePath is found', () => {
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       const noService = new Service(serverless);
 
       return expect(noService.load()).to.be.fulfilled;
@@ -156,6 +158,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -210,6 +213,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -264,6 +268,7 @@ describe('Service', () => {
         JSON.stringify(serverlessJSON));
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -319,6 +324,7 @@ describe('Service', () => {
         `module.exports = ${JSON.stringify(serverlessJSON)};`);
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -374,6 +380,7 @@ describe('Service', () => {
         `module.exports = new Promise(resolve => { resolve(${JSON.stringify(serverlessJSON)}) });`);
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -404,6 +411,7 @@ describe('Service', () => {
         'module.exports = function config() {};');
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -447,6 +455,7 @@ describe('Service', () => {
         YAML.dump(serverlessJSON));
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
@@ -468,6 +477,7 @@ describe('Service', () => {
         YAML.dump(serverlessYaml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load()).to.eventually.be
@@ -488,6 +498,7 @@ describe('Service', () => {
         YAML.dump(serverlessYaml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load()).to.eventually.be.fulfilled
@@ -513,6 +524,7 @@ describe('Service', () => {
         YAML.dump(serverlessYaml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load()).to.eventually.be.fulfilled
@@ -546,6 +558,7 @@ describe('Service', () => {
         YAML.dump(serverlessYaml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load()).to.eventually.be.fulfilled
@@ -577,6 +590,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load({ stage: 'dev' })).to.eventually.be.fulfilled
@@ -604,6 +618,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load()).to.eventually.be
@@ -620,6 +635,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serviceInstance = new Service(serverless);
 
       return expect(serviceInstance.load()).to.eventually.be
@@ -638,6 +654,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       const getVersion = sinon.stub(serverless.utils, 'getVersion');
       getVersion.returns('1.0.2');
       serviceInstance = new Service(serverless);
@@ -658,6 +675,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       const getVersion = sinon.stub(serverless.utils, 'getVersion');
       getVersion.returns('1.2.2');
       serviceInstance = new Service(serverless);
@@ -675,6 +693,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serverless.variables.service = serverless.service;
       serviceInstance = new Service(serverless);
 
@@ -713,6 +732,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless({ servicePath: tmpDirPath });
+      serverless.processedInput = { options: {} };
       serverless.service = new Service(serverless);
 
       return expect(serverless.service.load()).to.eventually.be.fulfilled
@@ -753,6 +773,7 @@ describe('Service', () => {
           YAML.dump(serverlessYml));
 
         const serverless = new Serverless({ servicePath: tmpDirPath });
+        serverless.processedInput = { options: {} };
         return expect(simulateRun(serverless)).to.eventually.be.fulfilled.then(() => {
           expect(() => serverless.service.validate()).to.not.throw(serverless.classes.Error);
         });
@@ -1007,6 +1028,7 @@ describe('Service', () => {
         YAML.dump(serverlessYml));
 
       const serverless = new Serverless();
+      serverless.processedInput = { options: {} };
       serverless.config.update({ servicePath: tmpDirPath });
       serviceInstance = new Service(serverless);
 
diff --git a/lib/plugins/package/lib/packageService.test.js b/lib/plugins/package/lib/packageService.test.js
index cda98723936..d5c9ac1caee 100644
--- a/lib/plugins/package/lib/packageService.test.js
+++ b/lib/plugins/package/lib/packageService.test.js
@@ -20,6 +20,7 @@ describe('#packageService()', () => {
 
   beforeEach(() => {
     serverless = new Serverless();
+    serverless.processedInput = { options: {} };
     packagePlugin = new Package(serverless, {});
     packagePlugin.serverless.cli = new serverless.classes.CLI();
     packagePlugin.serverless.service.functions = {
diff --git a/lib/plugins/print/print.test.js b/lib/plugins/print/print.test.js
index 5787492db38..3e6e8e7e64d 100644
--- a/lib/plugins/print/print.test.js
+++ b/lib/plugins/print/print.test.js
@@ -30,6 +30,7 @@ describe('Print', () => {
       region: 'us-east-1',
     };
     serverless.cli = new CLI(serverless);
+    serverless.processedInput = { options: {} };
     print = new PrintPlugin(serverless);
     print.serverless.cli = {
       consoleLog: sinon.spy(),
diff --git a/lib/utils/getServerlessConfigFile.test.js b/lib/utils/getServerlessConfigFile.test.js
index 6351828b989..87a84aab481 100644
--- a/lib/utils/getServerlessConfigFile.test.js
+++ b/lib/utils/getServerlessConfigFile.test.js
@@ -23,7 +23,10 @@ describe('#getServerlessConfigFile()', () => {
     const randomFilePath = path.join(tmpDirPath, 'not-a-serverless-file');
 
     writeFileSync(randomFilePath, 'some content');
-    return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then((result) => {
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: { servicePath: tmpDirPath },
+    })).to.be.fulfilled.then((result) => {
       expect(result).to.equal('');
     });
   });
@@ -32,7 +35,10 @@ describe('#getServerlessConfigFile()', () => {
     const serverlessFilePath = path.join(tmpDirPath, 'serverless.yml');
 
     writeFileSync(serverlessFilePath, 'service: my-yml-service');
-    return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then((result) => {
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: { servicePath: tmpDirPath },
+    })).to.be.fulfilled.then((result) => {
       expect(result).to.deep.equal({ service: 'my-yml-service' });
     });
   });
@@ -41,16 +47,35 @@ describe('#getServerlessConfigFile()', () => {
     const serverlessFilePath = path.join(tmpDirPath, 'serverless.yaml');
 
     writeFileSync(serverlessFilePath, 'service: my-yaml-service');
-    return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then((result) => {
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: { servicePath: tmpDirPath },
+    })).to.be.fulfilled.then((result) => {
       expect(result).to.deep.equal({ service: 'my-yaml-service' });
     });
   });
 
+  it('should return the file content if a foobar.yaml file is specified & found', () => {
+    const serverlessFilePath = path.join(tmpDirPath, 'foobar.yaml');
+
+    writeFileSync(serverlessFilePath, 'service: my-yaml-service');
+    return expect(getServerlessConfigFile({
+      processedInput: { options: { config: 'foobar.yaml' } },
+      config: { servicePath: tmpDirPath },
+    })).to.be.fulfilled.then(
+      (result) => {
+        expect(result).to.deep.equal({ service: 'my-yaml-service' });
+      });
+  });
+
   it('should return the file content if a serverless.json file is found', () => {
     const serverlessFilePath = path.join(tmpDirPath, 'serverless.json');
 
     writeFileSync(serverlessFilePath, '{ "service": "my-json-service" }');
-    return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then((result) => {
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: { servicePath: tmpDirPath },
+    })).to.be.fulfilled.then((result) => {
       expect(result).to.deep.equal({ service: 'my-json-service' });
     });
   });
@@ -62,7 +87,10 @@ describe('#getServerlessConfigFile()', () => {
       'module.exports = {"service": "my-json-service"};'
     );
 
-    return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then(
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: { servicePath: tmpDirPath },
+    })).to.be.fulfilled.then(
       (result) => {
         expect(result).to.deep.equal({ service: 'my-json-service' });
       }
@@ -76,7 +104,10 @@ describe('#getServerlessConfigFile()', () => {
       'module.exports = new Promise(resolve => { resolve({"service": "my-json-service"}); });'
     );
 
-    return expect(getServerlessConfigFile(tmpDirPath)).to.be.fulfilled.then(
+    return expect(getServerlessConfigFile(
+      { processedInput: { options: {} },
+        config: { servicePath: tmpDirPath },
+      })).to.be.fulfilled.then(
       (result) => {
         expect(result).to.deep.equal({ service: 'my-json-service' });
       }
@@ -90,7 +121,10 @@ describe('#getServerlessConfigFile()', () => {
       'module.exports = function config() {};'
     );
 
-    return expect(getServerlessConfigFile(tmpDirPath))
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: { servicePath: tmpDirPath },
+    }))
       .to.be.rejectedWith('serverless.js must export plain object');
   });
 
@@ -100,7 +134,10 @@ describe('#getServerlessConfigFile()', () => {
     writeFileSync(serverlessFilePath, 'service: my-yml-service');
     const cwd = process.cwd();
     process.chdir(tmpDirPath);
-    return expect(getServerlessConfigFile()).to.be.fulfilled
+    return expect(getServerlessConfigFile({
+      processedInput: { options: {} },
+      config: {},
+    })).to.be.fulfilled
       .then((result) => {
         process.chdir(cwd);
         expect(result).to.deep.equal({ service: 'my-yml-service' });