Skip to content

mongodb-developer/appwrite-nextjs-selfhosted-app

Repository files navigation

Next.js Todo App Β· Self-Hosted Appwrite + MongoDB

A full-stack Next.js todo application that demonstrates authentication, CRUD operations, and full-text search β€” all powered by a self-hosted Appwrite instance that uses MongoDB as its database engine.


πŸ—ΊοΈ Architecture

Browser (Next.js)
      β”‚
      β”‚  Appwrite Web SDK (REST/WebSocket)
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Appwrite Server   β”‚  ← self-hosted on Docker
β”‚  (Auth Β· Databases) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚  native driver
         β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚   MongoDB    β”‚  ← stores every document, index & user record
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Appwrite's Databases service maps directly onto MongoDB collections. Every todo you create, update, or delete is a MongoDB document. The full-text index on the title field is a MongoDB text index created by Appwrite under the hood.


βœ… Prerequisites

Before cloning this project you must have a running, self-hosted Appwrite instance backed by MongoDB.

Follow the official guide:
πŸ‘‰ Self-Hosting Appwrite with MongoDB

The guide walks you through spinning up Appwrite via Docker Compose and provision a self hosted MongoDB system.

Once Appwrite is running you will need:

Value Where to find it
Appwrite Endpoint The URL where Appwrite is reachable, e.g. http://localhost/v1
Project ID Appwrite Console β†’ your project β†’ Settings
API Key Appwrite Console β†’ project β†’ Settings β†’ API Keys (scopes: databases.*, collections.*, attributes.*)

πŸš€ Getting Started

1 Β· Clone the repository

git clone https://github.com/mongodb-developer/appwrite-nextjs-selfhosted-app.git
cd appwrite-nextjs-selfhosted-app

2 Β· Configure environment variables

cp .env.example .env

Edit .env and fill in your values:

NEXT_PUBLIC_APPWRITE_ENDPOINT=http://localhost/v1   # your Appwrite endpoint
NEXT_PUBLIC_APPWRITE_PROJECT_ID=<your-project-id>

3 Β· Install dependencies

setup-appwrite.mjs uses node-appwrite (listed under devDependencies), so install everything first:

npm install

4 Β· Scaffold the Appwrite backend (one-time)

The setup-appwrite.mjs script creates the database, collection, attributes, and a full-text index on the title field:

APPWRITE_API_KEY=<your-api-key> node setup-appwrite.mjs

Expected output:

βœ…  Database 'todos-db' created.
βœ…  Collection 'todos' created.
βœ…  Attribute 'title' created.
βœ…  Attribute 'completed' created.
βœ…  Attribute 'userId' created.
βœ…  Full-text index 'title_fulltext' created on 'title'.

πŸŽ‰  Setup complete! Database ID: todos-db  |  Collection ID: todos

The script is idempotent β€” safe to run again if something was already created.

5 Β· Run the app

npm run dev

Open http://localhost:3000 in your browser.


πŸ”„ CRUD Operations

All data operations use the Appwrite Web SDK (appwrite npm package) against the todos-db database and todos collection.

Create β€” add a todo

// src/app/todos/page.js  β†’  addTodo()
const doc = await databases.createDocument(
  DATABASE_ID,          // "todos-db"
  COLLECTION_ID,        // "todos"
  ID.unique(),          // auto-generated MongoDB ObjectId-style ID
  { title, completed: false, userId: user.$id },
  [
    Permission.read(Role.user(user.$id)),
    Permission.update(Role.user(user.$id)),
    Permission.delete(Role.user(user.$id)),
  ]
);

Each document is created with document-level permissions so only the owner can read, update, or delete it β€” even though the collection is readable by any authenticated user.

Read β€” list todos

// src/app/todos/page.js  β†’  fetchTodos()
const res = await databases.listDocuments(DATABASE_ID, COLLECTION_ID, [
  Query.equal("userId", user.$id),   // only this user's todos
  Query.orderDesc("$createdAt"),     // newest first
]);

Appwrite translates the Query helpers into MongoDB find filter documents before hitting the collection.

Update β€” toggle completed

// src/app/todos/page.js  β†’  toggleTodo()
const updated = await databases.updateDocument(
  DATABASE_ID,
  COLLECTION_ID,
  todo.$id,
  { completed: !todo.completed }   // partial update (MongoDB $set)
);

Only the completed field is changed β€” Appwrite performs a targeted $set rather than a full document replacement.

Delete β€” remove a todo

// src/app/todos/page.js  β†’  deleteTodo()
await databases.deleteDocument(DATABASE_ID, COLLECTION_ID, id);

A "Clear completed" bulk-delete button in the footer calls deleteTodo in parallel for all checked items.


πŸ” Full-Text Search

The setup script creates a MongoDB full-text index (type: "fulltext") on the title field:

// setup-appwrite.mjs
await databases.createIndex(
  DATABASE_ID, COLLECTION_ID,
  "title_fulltext",   // index name
  "fulltext",         // maps to a MongoDB text index
  ["title"]
);

The app uses Query.search() to leverage that index:

// src/app/todos/page.js  β†’  fetchTodos()
if (searchTerm.length >= 3) {
  queries.push(Query.search("title", searchTerm));
}

Key behaviours:

Behaviour Detail
Minimum 3 characters Prevents excessive queries on short input
Debounced 300 ms setTimeout clears previous timer on each keystroke
Combined with user filter Query.equal("userId", ...) is always applied, so users only ever see their own results
Clear button Resets both searchInput and searchTerm state, falling back to the full list

πŸ“ Project Structure

starter-for-nextjs/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ page.js          # Auth page (sign-in / register)
β”‚   β”‚   β”œβ”€β”€ todos/
β”‚   β”‚   β”‚   └── page.js      # Todos page (CRUD + search)
β”‚   β”‚   └── app.css          # Tailwind + custom styles
β”‚   └── lib/
β”‚       └── appwrite.js      # Appwrite client singleton
β”œβ”€β”€ setup-appwrite.mjs       # One-time backend scaffold script
β”œβ”€β”€ .env.example             # Environment variable template
└── package.json

πŸ”— Useful Links

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors