CAP Node.js Folder Structure

Detailed walkthrough of db/, srv/, app/, package.json, .cdsrc.json, and how they connect at runtime.

CAP Node.js Folder Structure

my-cap-app/
├── app/                         ← Fiori/SAPUI5 UI apps (optional)
│   └── my-ui/
│       ├── webapp/
│       └── ui5.yaml
│
├── db/                          ← Data layer
│   ├── schema.cds               ← Entity definitions
│   ├── data/                    ← CSV seed data for local dev
│   │   └── my.namespace-Books.csv
│   └── src/                     ← HANA-specific artifacts (hdbview, etc.)
│
├── srv/                         ← Service layer
│   ├── cat-service.cds          ← Service definition
│   └── cat-service.js           ← Custom handler (optional)
│
├── .cdsrc.json                  ← CDS runtime config
├── package.json                 ← npm config + cds section
└── mta.yaml                     ← MTA deployment descriptor (added later)

The db/ folder

This is where your data model lives. CDS compiles .cds files into SQL or HANA artifacts.

// db/schema.cds
namespace my.namespace;

entity Products {
  key ID       : UUID;
  name         : String(100);
  description  : localized String;  // ← auto i18n table
  price        : Decimal(10, 2);
  category     : Association to Categories;
}

entity Categories {
  key ID   : Integer;
  name     : String(50);
  products : Composition of many Products on products.category = $self;
}

The srv/ folder

Service definitions expose entities as OData endpoints.

// srv/cat-service.cds
using my.namespace from '../db/schema';

service CatalogService @(path: '/catalog') {
  entity Products as projection on my.namespace.Products;
  entity Categories as projection on my.namespace.Categories;

  // Read-only projection with extra annotations
  @readonly entity ProductView as projection on my.namespace.Products
    excluding { description };
}

Custom handlers (srv/cat-service.js)

const cds = require('@sap/cds');
module.exports = class CatalogService extends cds.ApplicationService {
  init() {
    this.before('CREATE', 'Products', req => {
      if (!req.data.price || req.data.price <= 0) {
        req.error(400, 'Price must be positive');
      }
    });
    return super.init();
  }
};

.cdsrc.json

{
  "requires": {
    "db": {
      "kind": "sqlite",
      "[production]": { "kind": "hana" }
    }
  },
  "features": { "fetch_csrf": true }
}

package.json — the cds section

{
  "cds": {
    "requires": { "db": { "kind": "sqlite" } },
    "hana": { "deploy-format": "hdbtable" }
  }
}

The cds key in package.json overrides .cdsrc.json and is the recommended place for config.

Sign in for progress tracking & Q&A →