Welcome to our tutorial on building a Nextjs todo app using Altogic, where we will guide you step-by-step to build a dynamic and starter To-Do App using the power of Nextjs 13 and Altogic. With this tutorial, you will learn how to create a To-Do App that is not only including frontend, but also connected with backend. You will discover how Nextjs makes it easy to build fast, efficient and interactive apps, and how Altogic handles the backend of your app, allowing you to focus on the frontend. With Altogic, you will add a touch of creativity and innovation that will make your To-Do App stand out from the rest. Get ready to start with this step-by-step guide on building a Nextjs todo app. We will also cover how to use the Altogic Client Library to create a simple to-do app.
What is Altogic?
Altogic backend as a service platform allows you to create and start running your backend apps in minutes. With your backend apps, you can manage your application data in a database, cache your data in memory, execute database transactions to ensure data integrity, run complex business logic through synchronous and asynchronous services, manage user sessions, schedule jobs to be executed at a specific time or interval, send and receive real-time messages through WebSockets and more.
What is Next.js?
Next.js is a JavaScript framework for building server-rendered React applications. It allows developers to easily create and deploy high-performance web apps with features such as automatic code splitting, server-side rendering, and static site generation. Next.js also includes a built-in development server and a powerful set of APIs for handling routing, configuration, and more.
Setting up Development Environment
To complete this tutorial, ensure you have installed the following tools and utilities on your local development environment.
- VsCode
- NodeJS
- Next.js
- You also need an Altogic Account. If you do not have one, you can create an account by signin up for Altogic.
Creating an Altogic Account
After creating an account, you will see the workspace and repository page. You can create a new app by clicking the + New app
button.

Click + New app
and follow the instructions;
- In the App name field, enter a name for the app.
- Enter your subdomain.
- Choose the deployment location.
- And select your free execution environment pricing plan.

For this tutorial, we will use the blank template. So, select the Blank template and click Next
.
note
In the template section, you can choose the template you want to use. Basic template creates a default user data model for your app, which is required by Altogic Client Library to store user data and manage authentication. If you don't need authentication, you can use the Blank template.
Later, if you want, you can easily create a new data model manually and from the App Settings → Authentication mark this new data model as your user data model.

Awesome! We have created our application; Now click/tap on the newly created app to launch the Designer. In order to access the app and use the Altogic client library, we should get envUrl
and clientKey
of this app.
Click the Home section in the left menu and copy the API base URL and Master client key for your app.

info
In this tutorial we don't need authentication. So, let's disable session based authentication from the App Settings → Client library keys → Master client key view of Altogic Designer.

By clicking the Enforce session
checkbox, you can disable session based authentication. Now, we are ready to start building our app.
Creating a Next.js project
Open your terminal and navigate to the directory where you want to create your project. Then run the following command to create a Next.js project.
npx [email protected]
# or
yarn create next-app
# or
pnpm create next-app

Designing the User Interface
Installing Tailwind
Open your terminal and navigate to the project directory. Then run the following commands to install Tailwind CSS. You can also follow the official Tailwind CSS documentation to install Tailwind CSS in your Next.js project.
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Add the paths to all of your template files in your tailwind.config.js file.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
Replace styles/global.css
with the following code:
@tailwind base;
@tailwind components;
@tailwind utilities;
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html,
body {
max-width: 100vw;
overflow-x: hidden;
}
a {
color: inherit;
text-decoration: none;
}
Creating the UI
Open the pages/index.js
file and replace the code with the following code:
export default function Home() {
return (
<div className="max-w-2xl mx-auto py-8 px-4 sm:py-12 sm:px-6 lg:max-w-7xl lg:px-8">
<form>
<div className="relative">
<input
placeholder="Add Todo"
className="w-full rounded-md border-gray-200 py-2.5 pr-10 pl-2 shadow-sm sm:text-sm border-2 border-dashed"
/>
<span className="absolute inset-y-0 right-0 grid w-10 place-content-center">
<button type="submit">
<span className="sr-only">Submit</span>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
id="send-icon"
className="w-7 h-7 text-gray-500"
>
<path
strokeLinecap="round"
stroke-strokelinejoin="round"
d="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</button>
</span>
</div>
</form>
<div className="flex items-center justify-between mt-2">
<div className="relative flex items-center">
<div className="flex items-center h-5">
<input
type="checkbox"
className="focus:ring-indigo-500 h-6 w-6 text-indigo-600 border-gray-300 rounded cursor-pointer"
/>
</div>
<div className="ml-3 text-sm w-full p-2 cursor-pointer">
<label className="font-medium text-gray-700 cursor-pointer"></label>
</div>
</div>
<div className="flex items-center px-2 py-2 text-sm font-medium rounded-md">
<button>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
className="lex-shrink-0 h-5 w-5"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</div>
</div>
</div>
);
}
Okay, now we have a basic UI for our app. Let's run the following command to start the development server.
npm run dev
Creating the Backend
As we mentioned earlier, we will use Altogic to create the backend for our app. Altogic is a serverless backend as a service platform that provides authentication, database, and other services. You can create a free account on Altogic and create a new app.
Creating Todo Model
- Click/tap on Models on the left sidebar.
- Click New on the right of the screen and select model.
- Set model name as todo.
- Ensure that the Enable timestamps is selected.
- Click Next

With using Altogic you can automatically generate Rest API for your models. You can also create custom API endpoints. Since we will use the Altogic Client Library, we won't use these endpoints.

We have created a todo
model, now we need to add fields for to our model. For this tutorial, let's create two fields for our model. One for the name of the todo and the other for the status of the todo.
Let's create the first field. We will create a text field for the name
of the todo.
- Click/tap on the todo model on the Models page.
- Click/tap on New Field at the right-top of the page.
- Select field type as Text Field then select Text.
- Set field name as
name
- Ensure that the Required is selected.
- Click Create.

Let's create the second field. We will create a boolean field for the isCompleted
of the todo.
- Click on New Field on the right-top of the page.
- Select Boolean.
- Set field name as
isCompleted
- Ensure that the Required is selected.
- Set default value expression false.

Ah yes, we have created our model and fields and completed the database design visually with using Altogic without any coding and complex configuration. Let’s move on to the front-end development.
Integrating Frontend with Backend
Now we have a basic UI for our app and a database design. Let’s integrate our frontend with the backend. We will use Altogic Client Library to integrate our frontend with the backend.
Installing Altogic Client Library
You can install the Altogic Client Library with using npm or yarn. Open your project directory and run the following command to install the Altogic Client Library.
# using npm
npm install altogic
# OR is using yarn
yarn add altogic
Let’s create a configs/
folder in the root of the project directory and create a altogic.js
file in the configs/
folder.
Open altogic.js
and paste below code block to export the altogic client instance.
// configs/altogic.js
import { createClient } from "altogic";
// This `envUrl` and `clientKey` is sample you need to create your own and replace it.
let envUrl = "https://todo.c1-na.altogic.com";
let clientKey = "e574fee1fb2b443...a8598ca68b7d8";
const altogic = createClient(envUrl, clientKey);
export default altogic;
note
You can find your envUrl
and clientKey
in the Home or Settings view of your app. You can also create a new environment and get the envUrl
and clientKey
for the new environment.
Creating State for Todo List
Let’s create a state for our todo list. We will use React Hooks to create our state. Open pages/index.js
and paste below code block to create our state.
const [todos, setTodos] = useState([]);
Fetching Todo List
The next step is to fetch the todo list from the database. We will use Altogic Client Library to fetch the todo list from the database. Open pages/index.js
and paste below code block to fetch the todo list from the database.
Let's create below function to fetch the todo list from the database. In this tutorial we will fetch the first 100 todos from the database. You can fetch the todos with using pagination and limit. You can also fetch the todos with using filters and sorting. You can find more information about fetching data from the database in the Altogic Client Library documentation.
export async function getServerSideProps() {
try {
const { data: todosFromDb, errors } = await altogic.db
.model("todo")
.page(1)
.limit(100)
.get();
if (errors) throw errors;
return { props: { todosFromDb } };
} catch (errorList) {
return { errorCode: errorList?.status || 404 };
}
}
export default function Home({ todosFromDb }) {
const [todos, setTodos] = useState(todosFromDb);
{
todos?.map((todo) => (
<div key={todo._id} className="flex items-center justify-between mt-2">
<div className="relative flex items-center">
<div className="flex items-center h-5">
<input
type="checkbox"
className="focus:ring-indigo-500 h-6 w-6 text-indigo-600 border-gray-300 rounded cursor-pointer"
/>
</div>
<div className="ml-3 text-sm w-full p-2 cursor-pointer">
<label className="font-medium text-gray-700 cursor-pointer">
{todo.name}
</label>
</div>
</div>
<div className="flex items-center px-2 py-2 text-sm font-medium rounded-md">
<button>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
className="lex-shrink-0 h-5 w-5"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</div>
</div>
));
}
Creating a Todo
Let's implement the functionality to create a todo and update the state after creating a todo in the database.
Open pages/index.js
and paste below code block to complete the functionality to create a todo.
const handleAddTodo = async (e) => {
e.preventDefault();
const [name] = e.target;
try {
const { data, errors } = await altogic.db.model("todo").create({
name: name.value,
});
if (errors) throw errors;
name.value = "";
setTodos([data, ...todos]);
} catch (errorList) {
alert(errorList?.items[0].message);
}
};
<form onSubmit={handleAddTodo}>
<div className="relative">
<input
placeholder="Add Todo"
className="w-full rounded-md border-gray-200 py-2.5 pr-10 pl-2 shadow-sm sm:text-sm border-2 border-dashed"
/>
<span className="absolute inset-y-0 right-0 grid w-10 place-content-center">
<button type="submit">
<span className="sr-only">Submit</span>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
id="send-icon"
className="w-7 h-7 text-gray-500"
>
<path
strokeLinecap="round"
stroke-strokelinejoin="round"
d="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</button>
</span>
</div>
</form>
Changing Todo Status
Let's implement the functionality to change the status of the todo and update the state after changing the status of the todo in the database.
So open pages/index.js
and paste below code block to complete the functionality to change the status of the todo.
const handleChangeStatus = async (todoId, newStatus) => {
try {
const { data: updatedTodo, errors } = await altogic.db
.model("todo")
.object(todoId)
.update({
isCompleted: newStatus,
});
if (errors) throw errors;
setTodos(todos.map((todo) => (todo._id === todoId ? updatedTodo : todo)));
} catch (errorList) {
alert(errorList?.items[0].message);
}
};
<div className="flex items-center h-5">
<input
type="checkbox"
className="focus:ring-indigo-500 h-6 w-6 text-indigo-600 border-gray-300 rounded cursor-pointer"
onChange={() => handleChangeStatus(todo._id, !todo.isCompleted)}
checked={todo.isCompleted}
/>
</div>
<div
className="ml-3 text-sm w-full p-2 cursor-pointer"
onClick={() => handleChangeStatus(todo._id, !todo.isCompleted)}
>
<label className="font-medium text-gray-700 cursor-pointer">
{todo.name}
</label>
</div>
Deleting the Todo
The last thing we need to do is to implement the functionality to delete the todo and update the state after deleting the todo in the database.
So open pages/index.js
and paste below code block to complete the functionality to delete the todo.
const handleDeleteTodo = async (todoId) => {
try {
const { errors } = await altogic.db.model("todo").object(todoId).delete();
if (errors) throw errors;
setTodos(todos.filter((todo) => todo._id !== todoId));
} catch (errorList) {
alert(errorList?.items[0].message);
}
};
<button onClick={() => handleDeleteTodo(todo._id)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
className="lex-shrink-0 h-5 w-5"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
Congratulations!✨
You have successfully created a todo app with Altogic.
Enhancing User Experience
Let's add some features to improve the user experience of our todo app. E.g., We can show the completed todos below the list and strike out to improve the user experience.
Let's add the sort function in altogic client library to sorting.
const { data: todosFromDb, errors } = await altogic.db
.model("todo")
.sort("updatedAt", "desc")
.sort("isCompleted", "asc")
.page(1)
.limit(100)
.get();
Let's our variable by using the sort function in javascript so that the sorting is not broken when the state changes. So let's add line-through class to cross out completed todos.
const sortedTodos = todos.sort((a, b) =>
a.isCompleted === b.isCompleted ? 0 : a.isCompleted ? 1 : -1
);
{
sortedTodos?.map((todo) => (
<div key={todo._id} className="flex items-center justify-between mt-2">
<div className="relative flex items-center">
<div className="flex items-center h-5">
<input
type="checkbox"
className="focus:ring-indigo-500 h-6 w-6 text-indigo-600 border-gray-300 rounded cursor-pointer"
onChange={() => handleChangeStatus(todo._id, !todo.isCompleted)}
checked={todo.isCompleted}
/>
</div>
<div
className="ml-3 text-sm w-full p-2 cursor-pointer"
onClick={() => handleChangeStatus(todo._id, !todo.isCompleted)}
>
<label
className={`font-medium text-gray-700 cursor-pointer ${
todo.isCompleted && "line-through"
}`}
>
{todo.name}
</label>
</div>
</div>
<div className="flex items-center px-2 py-2 text-sm font-medium rounded-md">
<button onClick={() => handleDeleteTodo(todo._id)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
aria-hidden="true"
className="lex-shrink-0 h-5 w-5"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</div>
</div>
));
}
Strategies for Optimizing Performance
If you want to add a search feature to your to-do application, you can add an index to the searched field with Altogic.
Let's open the Altogic designer and click on the name field of the todo model and select Indexed and Searchable properties and save them.

Conclusion
In this tutorial, we have learned how to create a todo app with Altogic. We have learned how to create a model, add fields, and create a todo app with Altogic. We have also learned how to add sorting feature to our todo app.
You can check out the source code of this tutorial.
You can access the demo of this tutorial from here.
Watch Youtube Video Tutorial in Turkish and English(soon)
If you want to access a more comprehensive example with features such as private todo creation, searching todo, inviting users, authentication, and real-time. You can check out Online Todo App or if you want to see more examples with Altogic, you can check out the showcase.