Skip to content

    Parsing and Compiling Models

    Use cds.compile, or one of the convenience shortcuts cds.parse and cds.load to parse and compile CDS models programmatically.

    cds.compile (models, options)

    This is the central function and API facade to parse and compile models. It supports different variants based on the type of the models argument as outlined in the following subsections.

    async cds.compile (‘file:…’, options) csn

    async cds.compile ([files], options) csn

    If the first argument is either a string starting with "file:", or an array of filenames, these files are read and compiled to a single CSN asynchronously.


    let csn = await cds.compile ('file:db')
    let csn = await cds.compile (['db','srv','app'])

    The given filenames are resolved to effective absolute filenames using cds.resolve.

    cds.compile (‘cdl’, options) csn

    If a single CDL string is passed as first argument, that CDL source is compiled to CSN synchroneously. Note: using from clauses are not resolved in this usage.


    let csn = cds.compile (`
      using {cuid} from '@sap/cds/common';
      entity Foo : cuid { foo:String }
      entity Bar as projection on Foo;
      extend Foo with { bar:String }

    cds.compile ({sources}, options) csn

    Allows to synchronously compile multiple named CDL or CSN sources, which allows to also resolve using from clauses.


    let csn = cds.compile ({
      'db/schema.cds': `
        using {cuid} from '@sap/cds/common';
        entity Foo : cuid { foo:String }
      'srv/services.cds': `
        using {Foo} from '../db/schema';
        entity Bar as projection on Foo;
        extend Foo with { bar:String }
      '@sap/cds/common.csn': `
          "cuid": { "kind": "aspect", "elements": {
            "ID": { "key":true, "type": "cds.UUID" }


    All variants of cds.compile() support the following options:


    One of:

    • 'parsed' → generates a parsed-only CSN
    • 'inferred' → + all query signatures inferred


    If true, definitions not reachable from service roots will be deleted. Use cds.env.features.skip_unused to control how the respective tree shaking mechanism works:

    • false → switched off
    • true → remove only definitions annotated with @cds.persistence.skip:'if-unused'
    • 'all' → remove all definitions not reachable from services

    If true, doc comments (/**...*/) are preserves in generated CSN


    If true, all $location properties are preserved in generated CSN


    Pass an empty array to collect all compiler messages in it.


    These are collection of model processors take a CDS model as input and generate different outputs.

    Static and Fluent API Variants

    All methods are available in a static and fluent variants.

    Static variants are invoked like that::

    let odata = cds.compile.for.odata(csn)
    let yaml =

    Fluent API variants are invoked like that:

    let odata = cds.compile(model).for.odata()
    let yaml = cds.compile(model).to.yaml()

    While static variants expect a parsed CSN, fluent variants also accept all of the source inputs as documented for cds.compile above.

     ↳ .for.odata (csn, options) unfolded csn

    Returns a new csn with unfolded structs and associations, depending on the specified options. In addition resolves certain common annotations to their OData vocabulary counterparts.

    Accepted options are those documented in the OData guide without cds.odata. prefix. If the options argument is a single string, it is interpreted as a shortcut to {flavor:...}


    let o1 = cds.compile(csn).for.odata ({
    let o2 = cds.compile(csn).for.odata ({flavor:'x4'})
    let o3 = cds.compile(csn).for.odata ('x4') //> shortcut to above

    Idempotent behavoir — Calling this function again on the same csn input will return the cached unfolded csn output from the former call.

     ↳ .to.json/yaml (csn) json

    Renders the given model to a formatted JSON or YAML string.

     ↳ .to.edm/edmx (csn, options) edm

    Compiles and returns an OData v4 EDM, repectively EDMX model object for the passed in model, which is expected to contain at least one service definition.

    Accepted options the same as documented for cds.compile.for.odata above, with one addition: If the model contains more than one service definition, use {service:...} option parameter to:

    • Either choose exactly one, for example, {service:'Catalog'}
    • Choose to return EDM objects for all, that means, {service:'all'}

    In case of the latter, a generator is returned that yields [ edm, {name} ] for each service. For example, use it as follows:

    // for one service
    let edm = cds.compile(csn).to.edm ({service:'Catalog'})
    console.log (edm)
    // for all services
    let all = cds.compile(csn).to.edm ({service:'all'})
    for (let [edm,{name}] of all)  console.log (name,edm)

     ↳ .to.hdbtable (csn)

     ↳ .to.hdbcds (csn)

    Generates hdbtable/view or hdbcds output. Returns a generator that yields [ src, {file} ] for each resulting .hdbtable, .hdbview, or .hdbcds file. For example, use it as follows:

    let all = (csn)
    for (let [src,{file}] of all)
      console.log (file,src)

     ↳ .to.sql (csn, options) SQL DDL

    Generates SQL DDL statements for the given model. The default returns an array with the generated statements.

    Accepted options are:

    • dialect: ‘plain’ | ‘sqlite’ | ‘postgres’ | ‘h2’ → chooses the dialect to generate
    • names: ‘plain’ | ‘quoted’ → allows to generate DDL using quoted names
    • as: ‘str’ → returns a string with concatenated DDL statements.


    let ddls1 = cds.compile(csn).to.sql()
    let ddls2 = cds.compile(csn).to.sql({dialect:'plain'})
    let script = cds.compile(csn).to.sql({as:'str'})

    cds.parse (cdl) csn

    This is an API facade for a set of functions to parse whole CDL models, individual CQL queries, or CQL expressions. The three main methods are offered as classic functions, as well as tagged template string functions. The individual methods are:

    CDL, cds.parse.cdl (cdl) csn

    Parses a source string in CDL syntax and returns it as a parsed model according to the CSN spec. It’s essentially a shortcut to cds.compile (..., {flavor:'parsed'}).


    let csn = CDL`entity Foo{}`
    let csn = cds.parse (`entity Foo{}`)  //= shortcut to:
    let csn = cds.parse.cdl (`entity Foo{}`)

    CQL, cds.parse.cql (cql) cqn

    Parses a source string in CQL syntax and returns it as a parsed query according to the CQN spec.


    let cqn = CQL`SELECT * from Foo`
    let cqn = cds.parse.cql (`SELECT * from Foo`)

    CXL, cds.parse.expr (cxl) cxn

    Parses a source string in CQL expression syntax and returns it as a parsed expression according to the CQN Expressions spec.


    let cxn = CXL` > 9`
    let cxn = cds.parse.expr (` > 9`)
    //> {xpr:[ {ref:['foo', 'bar']}, '>', {val:9} ] }

    cds.parse.xpr (cxl) xpr

    Convenience shortcut to cds.parse.expr(x).xpr


    let xpr = cds.parse.xpr (` > 9`)
    //> [ {ref:['foo', 'bar']}, '>', {val:9} ]

    cds.parse.ref (cxl) ref

    Convenience shortcut to cds.parse.expr(x).ref


    let ref = cds.parse.ref (``)
    //>= ['foo', 'bar']

    cds.load (files) csn

    Loads and parses a model from one or more files into a single effective model. It’s essentially a shortcut to cds.compile (..., {flavor:'inferred'}).


    Note: It’s recommended to omit file suffixes to leverage automatic loading from precompiled CSN files instead of CDL sources.

    // load a model from a single source
    const csn = await cds.load('my-model')
    // load a a model from several sources
    const csn = await cds.load(['db','srv'])
    // load relative to current working directory
    // load relative to current node module

    cds.resolve (paths) [filenames]

    Resolves the given source paths by fetching matching model source files, that is .cds or .csn files, including models for required services. In detail it works as follows:

    1. If paths is '*': paths = [ …cds.env.roots, …cds.requires.<srv>.model ]
    2. If paths is a single string: paths = [ paths ]
    3. For <each> in paths: …
      • if <each>.csn|cds exists → use it
      • if <each>/index.csn|cds exists → use it
      • if <each> is a folder → use all .csn|cds found in there

    Learn more about cds.env

    In effect it resolves and returns an array with the absolute filenames of the root cds model files to be used to invoke the compiler.

    If no files are found, undefined is returned.


    cds.env.folders           // = folders db, srv, app by default
    cds.env.roots             // + schema and services in cwd
    cds.resolve('*',false)    // + models in cds.env.requires
    cds.resolve('*')          // > the resolved existing files
    cds.resolve('db'])        // > the resolved existing files
    cds.resolve(['db','srv']) // > the resolved existing files
    cds.resolve('none')       // > undefined

    Try this in cds repl launched from your project root to see that in action.