Deep dive into db/, srv/, app/ directories — what belongs where and why. Package.json, .cdsrc.json, and profile configuration.
Where every file in a CAP project belongs, what .cdsrc.json controls, how profiles work, and how to structure a project that stays clean as it scales to dozens of services and entities.
my-project/
│
├── app/ ← Fiori / UI5 frontends
│ └── my-app/ ← One subfolder per UI app
│ └── webapp/
│
├── db/ ← Data model layer
│ ├── schema.cds ← Entity definitions
│ ├── data/ ← CSV seed data
│ │ └── my.ns-Books.csv
│ └── src/ ← HANA-specific artifacts (deployed to HANA only)
│ └── my-view.hdbview
│
├── srv/ ← Service layer
│ ├── catalog-service.cds ← Service definition
│ ├── catalog-service.js ← Custom handlers (same base name)
│ └── lib/ ← Shared utilities
│
├── .cdsrc.json ← CAP configuration
├── .env ← Local secrets (never commit this)
├── package.json
└── mta.yaml ← BTP deployment descriptor (added later)
db/ folder — your data layerdb/ contains everything related to what you store.
db/
├── schema.cds ← All entity definitions
├── data/ ← CSV files for local seed data
│ └── ns-Entity.csv ← Named: <namespace>-<Entity>.csv
└── src/ ← HANA-only artifacts
└── *.hdbview ← HANA Calculation Views, Stored Procs
Rules:
- Put all entity definitions in db/schema.cds (or split into multiple .cds files for large projects)
- CSV files in db/data/ are auto-loaded by cds watch into the in-memory SQLite database
- The db/src/ folder is only deployed to HANA, not SQLite — put native HANA SQL here
srv/ folder — your service layersrv/ contains everything related to what you expose and how you handle it.
srv/
├── catalog-service.cds ← OData service definition
├── catalog-service.js ← Custom handlers (matched by name)
├── admin-service.cds ← Another service (admin-only)
├── admin-service.js
└── lib/
└── helpers.js ← Shared code (not a CDS file)
Critical rule: The .js handler file must have the exact same base name as the .cds service file. CAP auto-connects them:
catalog-service.cds ←→ catalog-service.js ✅ Auto-wired
adminService.cds ←→ adminService.js ✅ Auto-wired
catalog-service.cds ←→ handlers.js ❌ NOT auto-wired
.cdsrc.json file — CAP configurationThis is the brain of your CAP project. It controls how CAP behaves in different environments.
{
"requires": {
"db": {
"kind": "sqlite",
"credentials": { "database": ":memory:" }
}
},
"features": {
"fetch_csrf": true
}
}
Important settings:
{
"requires": {
"db": {
"[development]": {
"kind": "sqlite",
"credentials": { "database": "db.sqlite" }
},
"[production]": {
"kind": "hana"
}
},
"auth": {
"[development]": { "kind": "mocked" },
"[production]": { "kind": "xsuaa" }
}
}
}
CAP uses profiles to switch config between dev and production. The profile is set via the NODE_ENV environment variable.
# Development (default)
cds watch # Uses [development] profile
# Production
NODE_ENV=production cds serve # Uses [production] profile
You can define your own profiles:
{
"requires": {
"db": {
"[test]": {
"kind": "sqlite",
"credentials": { "database": ":memory:" }
}
}
}
}
NODE_ENV=test npx jest
package.json — key CAP fields{
"name": "my-bookshop",
"dependencies": {
"@sap/cds": "^8.0.0", ← CAP runtime (required)
"@sap/cds-dk": "^8.0.0", ← CAP CLI tools (dev)
"express": "^4.18.0", ← Web framework
"@sap/hana-client": "^2.x" ← HANA driver (add for HANA)
},
"scripts": {
"start": "cds serve --production",
"watch": "cds watch",
"build": "cds build/all"
},
"cds": {
"requires": { ... } ← Can put cdsrc.json content here
}
}
Tip: For small projects, you can put your CAP config in
package.jsonunder the"cds"key instead of a separate.cdsrc.json.
As your project grows, split the data model across multiple files:
db/
├── common.cds ← Shared types and aspects
├── products.cds ← Product-related entities
└── orders.cds ← Order-related entities
In srv/catalog-service.cds, import what you need:
using { sap.capbookshop.Products } from '../db/products';
using { sap.capbookshop.Orders } from '../db/orders';
Putting business logic in .cds files
CDS files are schema/definition only. No JavaScript in .cds.
Naming handler file differently from service file
CatalogService.js won't wire to catalog-service.cds. Names must match exactly (with the same casing rules that CDS uses).
Committing .env to git
Always add .env to .gitignore. It contains secrets.
You now understand:
- [ ] What goes in db/, srv/, and app/
- [ ] How .cdsrc.json profiles switch between SQLite and HANA
- [ ] How handler files are auto-wired to service definitions
- [ ] How to split a large schema into multiple .cds files
In Lesson 5, we go deep into CDS syntax — the language you'll use to define everything.
Sign in for progress tracking & Q&A →