Write Your First Function
Build a function that stores and retrieves user bookmarks using Database and Cache. By the end, you will have a working API running on the edge with zero external dependencies.
What You Will Build
Section titled “What You Will Build”A bookmarks API with three endpoints:
POST /bookmarks— save a bookmark (writes to DB)GET /bookmarks— list bookmarks (reads from cache, falls back to DB)DELETE /bookmarks/:id— remove a bookmark (updates DB and invalidates cache)
Prerequisites
Section titled “Prerequisites”- Aerostack CLI installed (
npm install -g @aerostack/cli) - An Aerostack account with an active project
- Node.js 18+
-
Create the function scaffold
Terminal window mkdir my-bookmarks-api && cd my-bookmarks-apinpm init -ynpm install -D typescript @cloudflare/workers-types -
Set up TypeScript
Create
tsconfig.json:{"compilerOptions": {"target": "ES2022","module": "ES2022","moduleResolution": "bundler","lib": ["ES2022"],"types": ["@cloudflare/workers-types"],"strict": true,"outDir": "dist","rootDir": "src"},"include": ["src"]} -
Configure Aerostack
Create
aerostack.toml:name = "my-bookmarks-api"main = "src/index.ts"compatibility_date = "2024-12-01"# These bindings are provided by Aerostack when deployed.# For local dev, the CLI creates local instances automatically.[[d1_databases]]binding = "DB"database_name = "aerostack-core"database_id = "local"[kv_namespaces]binding = "CACHE" -
Create the database table
Create
schema.sqlfor local development:CREATE TABLE IF NOT EXISTS bookmarks (id INTEGER PRIMARY KEY AUTOINCREMENT,url TEXT NOT NULL,title TEXT NOT NULL,created_at TEXT DEFAULT (datetime('now')));Apply it locally:
Terminal window aerostack db execute --local --file=schema.sql -
Write the function
Create
src/index.ts:interface Env {DB: DatabaseCACHE: Cache}export default {async fetch(request: Request, env: Env): Promise<Response> {const url = new URL(request.url)const path = url.pathname// --- POST /bookmarks ---if (request.method === 'POST' && path === '/bookmarks') {const body = await request.json<{ url: string; title: string }>()if (!body.url || !body.title) {return Response.json({ error: 'url and title are required' }, { status: 400 })}const result = await env.DB.prepare('INSERT INTO bookmarks (url, title) VALUES (?, ?) RETURNING *').bind(body.url, body.title).first()// Invalidate cache so next GET fetches fresh dataawait env.CACHE.delete('bookmarks:all')return Response.json(result, { status: 201 })}// --- GET /bookmarks ---if (request.method === 'GET' && path === '/bookmarks') {// Try cache firstconst cached = await env.CACHE.get('bookmarks:all', 'json')if (cached) {return Response.json(cached, {headers: { 'X-Cache': 'HIT' }})}// Cache miss — query DBconst { results } = await env.DB.prepare('SELECT * FROM bookmarks ORDER BY created_at DESC').all()// Store in cache for 5 minutesawait env.CACHE.put('bookmarks:all', JSON.stringify(results), {expirationTtl: 300})return Response.json(results, {headers: { 'X-Cache': 'MISS' }})}// --- DELETE /bookmarks/:id ---if (request.method === 'DELETE' && path.startsWith('/bookmarks/')) {const id = path.split('/').pop()await env.DB.prepare('DELETE FROM bookmarks WHERE id = ?').bind(id).run()await env.CACHE.delete('bookmarks:all')return Response.json({ deleted: true })}return Response.json({ error: 'Not found' }, { status: 404 })}} -
Test locally
Terminal window aerostack devIn another terminal:
Terminal window # Create a bookmarkcurl -X POST http://localhost:8787/bookmarks \-H "Content-Type: application/json" \-d '{"url": "https://aerostack.dev", "title": "Aerostack Docs"}'# List bookmarks (first call = cache MISS, second = HIT)curl http://localhost:8787/bookmarks -i# Delete itcurl -X DELETE http://localhost:8787/bookmarks/1 -
Deploy
Terminal window aerostack deploy functionThis uploads your function to your Aerostack project. The platform wires up the real database and cache bindings automatically — no configuration changes needed.
What Just Happened
Section titled “What Just Happened”Your function is now running on Cloudflare’s edge in 300+ data centers. It has:
- A database for persistent storage (
env.DB) - A cache for fast key-value lookups (
env.CACHE) - Automatic TLS, DDoS protection, and global distribution
- Zero cold start overhead
You wrote standard Cloudflare Workers code. Aerostack handled the infrastructure.
Going Further
Section titled “Going Further”This tutorial used two of the six platform bindings. To explore the rest:
- Platform bindings reference — code examples for DB, Cache, Queue, AI, Vector Search, and Storage
- Patterns and recipes — production-ready architectures for REST APIs, queue consumers, RAG pipelines, and more