08 · Running CAP Locally

Use cds watch for hot-reload development, explore the built-in Fiori launchpad, and test endpoints with REST clients.

Lesson 8 — Running CAP Locally with cds watch

What you'll learn

Everything about the cds watch development server — hot reload, the Fiori launchpad, the CAP REPL, testing with REST Client, and the mock authentication system for testing secured services locally.


cds watch — your daily driver

cds watch starts a development server that watches all .cds and .js files and restarts automatically when you save:

cds watch
[cds] - model loaded from 3 file(s)
[cds] - connect to db > sqlite { database: ':memory:' }
[cds] - serving CatalogService { path: '/odata/v4/catalog' }
[cds] - serving AdminService   { path: '/odata/v4/admin' }
[cds] - server listening on { url: 'http://localhost:4004' }

What cds watch does:

  1. Compiles all .cds files into an in-memory model
  2. Creates an in-memory SQLite database
  3. Loads CSV files from db/data/ as seed data
  4. Starts an Express HTTP server on port 4004
  5. Watches for file changes and restarts

The built-in welcome page

Open http://localhost:4004 — you'll see:

Welcome to cds.services

Web Applications
  /webapp  → (your Fiori app if configured)

Service Endpoints  
  /odata/v4/catalog  → CatalogService

$metadata            → Full OData metadata

⚙ Fiori Preview available

Click any service endpoint to open the OData service document.


Using the built-in Fiori launchpad

CAP includes a built-in Fiori preview for annotated services:

http://localhost:4004/$fiori-preview?service=CatalogService&entity=Books

This gives you a real Fiori List Report UI backed by your service — useful for testing Fiori annotations before connecting a real UI app.


Testing with VS Code REST Client

Create a file test/catalog.http (the .http extension activates the REST Client plugin):

### Get all books
GET http://localhost:4004/odata/v4/catalog/Books

### Filter books under $20
GET http://localhost:4004/odata/v4/catalog/Books?$filter=price lt 20

### Get a single book by ID
GET http://localhost:4004/odata/v4/catalog/Books(guid'f1f1f1f1-0000-0000-0000-000000000001')

### Create a book
POST http://localhost:4004/odata/v4/catalog/Books
Content-Type: application/json

{
  "title": "Clean Architecture",
  "author": "Robert C. Martin",
  "price": 39.99,
  "stock": 25
}

### Update a book
PATCH http://localhost:4004/odata/v4/catalog/Books(guid'...')
Content-Type: application/json

{ "price": 34.99 }

### Delete a book
DELETE http://localhost:4004/odata/v4/catalog/Books(guid'...')

Click Send Request above each block to execute it.


Mock authentication for secured services

When your service uses @requires, you need to pass a user for local testing:

In .cdsrc.json:

{
  "requires": {
    "auth": {
      "kind": "mocked",
      "users": {
        "alice": { "roles": ["admin", "viewer"] },
        "bob":   { "roles": ["viewer"] },
        "guest": { "roles": [] }
      }
    }
  }
}

In REST Client — send as Basic Auth:

### Test as admin
GET http://localhost:4004/odata/v4/admin/Books
Authorization: Basic alice:alice

### Test as regular viewer
GET http://localhost:4004/odata/v4/catalog/Books
Authorization: Basic bob:bob

The password for mocked users is the same as the username. This only works in development mode.


The CAP REPL

The REPL lets you interact with your CAP model programmatically:

cds repl
// In the REPL:
> await SELECT.from('com.bookshop.Books')
// Returns all books from the local SQLite

> await INSERT.into('com.bookshop.Books').entries({
    title: 'REPL Test Book',
    price: 9.99,
    stock: 10
  })
// Inserts a record

> cds.model.definitions['com.bookshop.Books']
// Inspect the compiled model definition

This is extremely useful for debugging queries without needing a running service.


Persistent SQLite (not in-memory)

By default, cds watch uses an in-memory SQLite database — data resets every time you restart. For persistent local data:

.cdsrc.json:

{
  "requires": {
    "db": {
      "kind": "sqlite",
      "credentials": { "database": "db/bookshop.db" }
    }
  }
}
# Deploy schema to the SQLite file (run once)
cds deploy --to sqlite

# Then watch — data persists across restarts
cds watch

Tip: Add db/*.db to your .gitignore — you don't want to commit the local database.


Useful CLI options

# Run on a different port
cds watch --port 4005

# Watch only (no browser auto-open)
cds watch --open false

# Run in production mode (no mock auth, no hot reload)
cds serve --production

# Build all (compiles CDS for deployment)
cds build/all

# Show compiled model
cds compile db/schema.cds --to json
cds compile srv/catalog-service.cds --to edmx  # OData EDMX

Checkpoint ✓

In Lesson 9 we explore OData V4 — what's actually happening when CAP handles those $filter, $expand, and $select queries.

Sign in for progress tracking & Q&A →