├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── ci-config.sample.txt ├── env └── .env.local ├── lambda.js ├── models └── Dog.js ├── next.config.js ├── package.json ├── pages ├── _document.js └── index.js ├── server.js ├── serverless-vpc-variables.yml ├── serverless.yml ├── static ├── images │ └── bg.jpeg └── scss │ └── main.scss └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "globals": { 5 | "window": "window", 6 | }, 7 | "rules": { 8 | "max-len": 'off', 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | .sass-cache/ 63 | .serverless 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Belong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nextjs-serverless 2 | Deploying a next JS site to serverless. 3 | 4 | ### Running it locally 5 | 6 | First install the dependencies 7 | ``` 8 | yarn install 9 | ``` 10 | 11 | You will also need to install [DynamoDB locally](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html). 12 | 13 | To start DynamoDB run, 14 | ``` 15 | java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb 16 | ``` 17 | For Development, 18 | ``` 19 | yarn run dev 20 | ``` 21 | 22 | 23 | ### Deploying it on Lambda 24 | 25 | Ensure you populate the serverless-vpc-variables.yml file with 26 | the values from your infrastucture against the various variables 27 | defined. 28 | 29 | 30 | Creating a domain. 31 | ``` 32 | serverless create_domain --stage staging 33 | ``` 34 | It might take about 40 minutes for the domain to initialize. 35 | 36 | 37 | Post that, deploy the serverless stack using the command 38 | ``` 39 | SLS_DEBUG=* serverless deploy --stage staging # For staging 40 | SLS_DEBUG=* serverless deploy --stage production # For production 41 | ``` 42 | -------------------------------------------------------------------------------- /ci-config.sample.txt: -------------------------------------------------------------------------------- 1 | # Test 2 | yarn run lint 3 | 4 | # Deployment 5 | s3Upload /static 6 | serverless deploy --stage stage_name --staticPath s3Url 7 | -------------------------------------------------------------------------------- /env/.env.local: -------------------------------------------------------------------------------- 1 | AWS_ACCESS_KEY='access_key' 2 | AWS_ACCESS_SECRET='secret' 3 | SERVICE_AWS_REGION='ap-south-1' 4 | DB_PREFIX='APP_NAMESPACE_' 5 | # The path to S3 bucket/CDN for serving static assets. Leave empty for dev env. 6 | STATIC_PATH='' 7 | -------------------------------------------------------------------------------- /lambda.js: -------------------------------------------------------------------------------- 1 | const awsServerlessExpress = require('aws-serverless-express'); 2 | const app = require('./server'); 3 | 4 | const binaryMimeTypes = [ 5 | '*/*' 6 | ]; 7 | 8 | const server = awsServerlessExpress.createServer(app, null, binaryMimeTypes); 9 | 10 | exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context); 11 | -------------------------------------------------------------------------------- /models/Dog.js: -------------------------------------------------------------------------------- 1 | const dynamoose = require('dynamoose'); 2 | 3 | const dogSchema = new dynamoose.Schema({ 4 | breed: { 5 | hashKey: true, 6 | type: String, 7 | required: true, 8 | }, 9 | name: { 10 | rangeKey: true, 11 | type: String, 12 | required: true, 13 | }, 14 | }, { 15 | timestamps: true, 16 | throughput: 5, 17 | useNativeBooleans: true, 18 | useDocumentTypes: true, 19 | }); 20 | 21 | module.exports = dynamoose.model(`${process.env.DB_PREFIX}Dog`, dogSchema); 22 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | // next.config.js 2 | const path = require('path'); 3 | const withSass = require('@zeit/next-sass'); 4 | require('dotenv').config({ path: path.resolve(__dirname, `./env/${process.env.ENV_FILE}`) }); 5 | 6 | const { STATIC_PATH } = process.env; 7 | 8 | module.exports = Object.assign( 9 | {}, 10 | withSass(), 11 | { 12 | publicRuntimeConfig: { 13 | STATIC_PATH, 14 | }, 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-serverless", 3 | "version": "1.0.0", 4 | "description": "Simple setup to deploy nextjs with express to lambda", 5 | "main": "index.js", 6 | "repository": "https://github.com/belongco/nextjs-serverless-setup.git", 7 | "contributors": [ 8 | { 9 | "name": "Vivek Kaarthek", 10 | "email": "kaarthek@belong.co" 11 | }, 12 | { 13 | "name": "Phani Kumar", 14 | "email": "phani@belong.co" 15 | } 16 | ], 17 | "license": "MIT", 18 | "scripts": { 19 | "lint": "eslint --fix pages/", 20 | "build": "next build", 21 | "dev": "ENV_FILE=.env.local NODE_ENV=development node server.js" 22 | }, 23 | "dependencies": { 24 | "@zeit/next-sass": "^0.2.0", 25 | "aws-serverless-express": "^3.2.0", 26 | "dotenv": "^5.0.1", 27 | "dynamoose": "^0.8.7", 28 | "express": "^4.16.3", 29 | "next": "5.1.0", 30 | "node-sass": "^4.9.0", 31 | "prop-types": "^15.6.1", 32 | "react": "^16.3.2", 33 | "react-dom": "^16.3.2", 34 | "serverless-apigw-binary": "^0.4.4", 35 | "serverless-apigwy-binary": "^0.1.0", 36 | "serverless-domain-manager": "^2.4.0", 37 | "serverless-http": "^1.5.5" 38 | }, 39 | "devDependencies": { 40 | "babel-eslint": "^8.2.3", 41 | "eslint": "^4.19.1", 42 | "eslint-config-airbnb": "^16.1.0", 43 | "eslint-plugin-import": "^2.12.0", 44 | "eslint-plugin-jsx-a11y": "^6.0.3", 45 | "eslint-plugin-react": "^7.8.2", 46 | "serverless": "1.27.3" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pages/_document.js: -------------------------------------------------------------------------------- 1 | import Document, { Head, Main, NextScript } from 'next/document'; 2 | 3 | 4 | export default class DocumentWrapper extends Document { 5 | render() { 6 | return ( 7 | 8 |
9 | 10 |