Quickstart
This Quickstart guide will walk you through how to build a task list application with TypeScript, Next.js, and React. If you are new to these technologies, we recommend you go through the official React, Next.js, and TypeScript tutorials first.
Prerequisites
Before you get started, make sure you have the following installed:
- Node.js v18.17 or later
- npm v9 or later
- git v2.14.1 or later
- You will also need to create an AWS account. Note that AWS Amplify is part of the AWS Free Tier.
Create a project
First, you will need to create a new Next.js app. The following command will create a Next.js app in a directory called next-amplify-gen2
.
1npm create next-app@14 -- next-amplify-gen2 --typescript --eslint --no-app --no-src-dir --no-tailwind --import-alias '@/*'2cd next-amplify-gen2
The easiest way to get started with AWS Amplify is through npm with create-amplify
.
1npm create amplify@latest
1? Where should we create your project? (.) # press enter
Running this command will scaffold a lightweight Amplify project in your current project with the following files:
1├── amplify/2│ ├── auth/3│ │ └── resource.ts4│ ├── data/5│ │ └── resource.ts6│ ├── backend.ts7│ └── package.json8├── node_modules/9├── .gitignore10├── package-lock.json11├── package.json12└── tsconfig.json
Start local dev server
Let's start a local dev server for your app development. For the frontend, run npm run dev
to spin up a localhost
dev server with the default Next.js template.
1npm run dev
For the backend, we're going to start a cloud sandbox environment. Amplify gives every developer a personal cloud sandbox environment that provides isolated development spaces to rapidly build, test, and iterate. When you're working with a team, each developer will have their own personal cloud sandbox. In a new terminal window, run the following command:
1npx amplify sandbox
You should now have these two commands running concurrently in different terminal windows.
Build a backend
Next, we will add data and auth capabilities to the app.
Add data
Each of the resource.ts
files is where you define the corresponding backend resource. If you open up the /amplify/data/resource.ts
file in your text editor, you will see some generated code already there:
1// amplify/data/resource.ts2import { type ClientSchema, a, defineData } from '@aws-amplify/backend';3
4/*== STEP 1 ===============================================================5The section below creates a Todo database table with a "content" field. Try6adding a new "isDone" field as a boolean. The authorization rules below7specify that owners, authenticated via your Auth resource, can "create",8"read", "update", and "delete" their own records. Public users,9authenticated via an API key, can only "read" records.10=========================================================================*/11const schema = a.schema({12 Todo: a13 .model({14 content: a.string()15 })16 .authorization([a.allow.owner(), a.allow.public().to(['read'])])17});18
19export type Schema = ClientSchema<typeof schema>;20
21export const data = defineData({22 schema,23 authorizationModes: {24 defaultAuthorizationMode: 'apiKey',25 // API Key is used for a.allow.public() rules26 apiKeyAuthorizationMode: {27 expiresInDays: 3028 }29 }30});31
32/*== STEP 2 ===============================================================33Go to your frontend source code. From your client-side code, generate a34Data client to make CRUDL requests to your table. (THIS SNIPPET WILL ONLY35WORK IN THE FRONTEND CODE FILE.)36
37Using JavaScript or Next.js React Server Components, Middleware, Server 38Actions, or Pages Router? Review how to generate Data clients for those use39cases: https://docs.amplify.aws/gen2/build-a-backend/data/connect-to-API/40=========================================================================*/41
42/*43"use client"44import { generateClient } from "aws-amplify/data";45import { type Schema } from "@/amplify/data/resource";46
47const client = generateClient<Schema>() // use this Data client for CRUDL requests48*/49
50/*== STEP 3 ===============================================================51Fetch records from the database and use them in your frontend component.52(THIS SNIPPET WILL ONLY WORK IN THE FRONTEND CODE FILE.)53=========================================================================*/54
55/* For example, in a React component, you can use this snippet in your56 function's RETURN statement */57// const { data: todos } = client.models.Todo.list()58
59// return <ul>{todos.map(todo => <li key={todo.id}>{todo.content}</li>)}</ul>
Learn moreWhat is a schema?
The schema generated by Amplify is for a to-do app. A schema is a blueprint for how our app's data will be organized. Within the schema, we will define models which will correspond to a database table—Todo
in the above code. Finally, we will define fields which are attributes that each data instance will have—in the generated code, the fields are name
and description
. Each field will have a type attached to it—in the above examples, we are stating that both name
and description
are strings.
Let's make a quick change to our data model and add a done
field. This will be a boolean
, which can be set to true
or false
depending on whether our to-do list item is complete. Let's also add a priority field, which will be an enum
. This field type will allow for just a few options to be stored—low, medium, or high.
We've removed the default comments to shorten the code below; however, you can choose to keep them for help in connecting to your frontend resources.
1// amplify/data/resource.ts2import { type ClientSchema, a, defineData } from '@aws-amplify/backend';3
4// ...5
6const schema = a.schema({7 Todo: a8 .model({9 content: a.string(),10+ done: a.boolean(),11+ priority: a.enum(['low', 'medium', 'high'])12 })13 .authorization([a.allow.owner(), a.allow.public().to(['read'])]),14});15
16export type Schema = ClientSchema<typeof schema>;17
18export const data = defineData({19 schema,20 authorizationModes: {21 defaultAuthorizationMode: 'apiKey',22 // API Key is used for a.allow.public() rules23 apiKeyAuthorizationMode: {24 expiresInDays: 30,25 },26 },27});28
29// ...
Once you save your changes to the data model, your changes will be deployed in seconds within your cloud sandbox.
Our Todo data model also has authorization set up. Our model has the authorization
method chained to it, which you can add rules to. In our example, we are allowing an owner, or the person who creates the Todo instance, to perform all actions on the data they own. We are also allowing all page viewers, including unauthenticated users, to read data. These can be modified; for example, we could remove the .to(['read'])
and allow all visitors to perform all actions on data. We could also add permissions for signed-in users or users who belong to user groups such as Admin
. You can learn more about all options for authorization in the customize your auth rules section of the docs.
Let's remove public access.
1.authorization([a.allow.owner()]),
Then, you will see the defineData
function, which has our schema and authorization configuration passed in as arguments. We have an apiKey
set up to enable public access. Let's change our defaultAuthorizationMode
to userPool
instead so that the default is to use user authentication.
1export const data = defineData({2 schema,3 authorizationModes: {4 defaultAuthorizationMode: 'userPool',5 },6});
The definitions are imported and set in the backend
file. We will not need to change anything in this file right now, but you can see its contents, which define a backend with our data and auth configurations from their respective files.
1// amplify/backend.ts2import { defineBackend } from '@aws-amplify/backend';3import { auth } from './auth/resource.js';4import { data } from './data/resource.js';5
6defineBackend({7 auth,8 data9});
Add authentication
Now let's work on our authentication configuration. Similar to the data/resource.ts
we just worked on, the auth/resource.ts
file has code to define our authentication configuration. In this case, setting the authentication method to log in with email.
1// amplify/auth/resource.ts2import { defineAuth } from '@aws-amplify/backend';3
4/**5 * Define and configure your auth resource6 * When used alongside data, it is automatically configured as an auth provider for data7 * @see https://docs.amplify.aws/gen2/build-a-backend/auth8 */9export const auth = defineAuth({10 loginWith: {11 email: true,12 // add social providers13 externalProviders: {14 /**15 * first, create your secrets using `amplify sandbox secret`16 * then, import `secret` from `@aws-amplify/backend`17 * @see https://docs.amplify.aws/gen2/deploy-and-host/sandbox-environments/features/#setting-secrets18 */19 // loginWithAmazon: {20 // clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),21 // clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET'),22 // }23 }24 },25 /**26 * enable multifactor authentication27 * @see https://docs.amplify.aws/gen2/build-a-backend/auth/manage-mfa28 */29 // multifactor: {30 // mode: 'OPTIONAL',31 // sms: {32 // smsMessage: (code) => `Your verification code is ${code}`,33 // },34 // },35 userAttributes: {36 /** request additional attributes for your app's users */37 // profilePicture: {38 // mutable: true,39 // required: false,40 // },41 }42});
Let's customize the verification email for our app. We can add a subject line by defining an object with email authentication properties. Again, we have removed comments for brevity.
1// amplify/auth/resource.ts2import { defineAuth } from '@aws-amplify/backend';3
4export const auth = defineAuth({5 loginWith: {6- email: true,7+ email: {8+ verificationEmailSubject: 'Welcome! Verify your email!'9+ },10 // add social providers11 externalProviders: {12 }13 }14});
Build UI
Let's add UI that connects to the backend data and auth resources.
Add a login form
First, install the Amplify UI component library:
1npm add @aws-amplify/ui-react
Next, in your app's pages/_app.tsx
, add the following imports and wrap your App in the withAuthenticator
function:
1// pages/_app.tsx2import { withAuthenticator } from '@aws-amplify/ui-react';3import { Amplify } from 'aws-amplify';4import config from '@/amplifyconfiguration.json';5import '@aws-amplify/ui-react/styles.css';6import type { AppProps } from 'next/app';7
8// configure the Amplify client library with the configuration generated by `amplify sandbox`9Amplify.configure(config);10
11function App({ Component, pageProps }: AppProps) {12 return <Component {...pageProps} />;13}14
15export default withAuthenticator(App);
Run your application with npm run dev
and navigate to http://localhost:3000
. You should now see the authenticator, which is already configured and ready for your first sign-up! Create a new user account, confirm the account through email, and then sign in.
View list of to-do items
Now, let's display data on our app's frontend. Modify your app's home page file, pages/index.tsx
, with the following code:
1// pages/index.tsx2import { useState, useEffect } from 'react';3import { generateClient } from 'aws-amplify/data';4import { Schema } from '@/amplify/data/resource';5
6// generate your data client using the Schema from your backend7const client = generateClient<Schema>();8
9export default function HomePage() {10 const [todos, setTodos] = useState<Schema['Todo'][]>([]);11
12 async function listTodos() {13 // fetch all todos14 const { data } = await client.models.Todo.list();15 setTodos(data);16 }17
18 useEffect(() => {19 listTodos();20 }, []);21
22 return (23 <main>24 <h1>Hello, Amplify 👋</h1>25 <ul>26 {todos.map((todo) => (27 <li key={todo.id}>{todo.content}</li>28 ))}29 </ul>30 </main>31 );32}
Once you save the file and navigate back to http://localhost:3000
, you should see an empty list of to-dos.
Create a new to-do item
Let's update the return statement of the above component to also have a button for creating a new to-do list item, prompting the user to add the title and description. In a production app, you would want to create a full form, and run the create method on form submission.
1// pages/index.tsx2// ...3 return (4 <main>5 <h1>Hello, Amplify 👋</h1>6 <button onClick={async () => {7 // create a new Todo with the following attributes8 const { errors, data: newTodo } = await client.models.Todo.create({9 // prompt the user to enter the title10 content: window.prompt("title"),11 done: false,12 priority: 'medium'13 })14 console.log(errors, newTodo);15 }}>Create </button>16
17 <ul>18 {todos.map((todo) => (19 <li key={todo.id}>{todo.content}</li>20 ))}21 </ul>22 </main>23 );24}
Create a couple of to-dos, then refresh the page to see them. You can also subscribe to new to-dos in your useEffect
to have them live reload on the page.
1useEffect(() => {2 const sub = client.models.Todo.observeQuery()3 .subscribe(({ items }) => setTodos([...items]))4
5 return () => sub.unsubscribe()6}, []);
Terminate dev server
Go to localhost
in the browser to make sure you can now log in and create and list to-dos. You can end your development session by shutting down the frontend dev server and cloud sandbox. The sandbox prompts you to delete your backend resources. While you can retain your backend, we recommend deleting all resources so you can start clean again next time.
Deploy and host a fullstack branch
Now that your app is working, let's deploy it to a shared fullstack branch so you can share the project with your team. Amplify offers a fully managed hosting service with CI/CD built in, making it easy to set up production and staging environments with Git branches. In Gen 2, every Git branch in your repository maps 1:1 to a fullstack branch in Amplify.
Create remote Git repository
If you already have your project remotely hosted in a Git repository, you can skip this step. Otherwise, navigate to your preferred Git provider, and add your project to a new repository. Amplify supports GitHub, AWS CodeCommit, GitLab, and Bitbucket.
Connect branch in the Amplify console
- To get started with Gen 2, log in to the AWS console and navigate to your preferred Region. (The Amplify console is available in 19 Regions).
- If you have never created apps with Amplify before, choose Create an app from the purple banner (top screenshot). If you have Amplify apps, you can find the option under New app > Build an app (Gen 2).
- In the Git provider screen, choose Option 2: Start with an existing app. Connect the repository you just deployed and pick a branch. Review all of your settings to ensure everything is set up correctly. Choose Save and deploy to deploy your web app to the AWS global content delivery network (CDN).
- That's it! Your app backend and frontend will now take ~5 minutes to build and deploy.
Manage fullstack branch
The new Amplify console gives you a central place to manage your branches, hosting settings, CI/CD builds, and backend resources. Even though you can access backend resources directly from AWS service consoles, the Amplify console offers built-in user and data administration.