Skip to content

Project structure

A “Vertex project” is any directory that contains both sfdx-project.json and vertex.jsonc (or vertex.json) at the root. Vertex reuses the standard Salesforce project layout so the output of vertex build can be deployed with the sf CLI without extra config.

my-project/
├── sfdx-project.json
├── vertex.jsonc
└── src/
└── hello.vtx

sfdx-project.json is the Salesforce project marker (Vertex reads sourceApiVersion from it). vertex.jsonc is the Vertex project marker and also configures the source directory, output directory, and clean behavior. Run vertex init to scaffold one with recommended defaults.

sfdx-project.json:

{
"packageDirectories": [
{ "path": "force-app", "default": true }
],
"sourceApiVersion": "66.0"
}

vertex.jsonc (the defaults vertex init writes):

{
"src": "src",
"out": "force-app/main/vertex/classes",
"clean": true
}

See Config file for the full schema and defaults.

my-project/
├── sfdx-project.json
├── vertex.jsonc
├── src/
│ └── hello.vtx
└── force-app/
└── main/
└── vertex/
└── classes/
├── Hello.cls
└── Hello.cls-meta.xml

Each .vtx file produces one Apex class. The class name is the file name capitalized (hello.vtx becomes Hello.cls).

The output lands under main/vertex/classes/ rather than main/default/classes/ to keep Vertex-generated Apex in its own metadata folder, isolated from any hand-written Apex under main/default/. This is why "clean": true is safe by default. You can change the output path via the out field in vertex.jsonc.

Each .vtx file is a module. The module name is the file path relative to src/, without the extension, using / as the separator.

src/billing/invoice.vtx # module: billing/invoice
src/shared/utils.vtx # module: shared/utils

Import another module by its module path:

import billing.invoice
import shared.utils
let i = invoice.total(...)

See Modules & Imports for the full rules (public/private visibility, cyclic-import detection, re-export rules).

Files ending in _test.vtx are test modules. They may import non-test modules, but non-test modules may not import them.

src/
├── invoice.vtx
└── invoice_test.vtx # @Test functions live here

Run them with vertex test (see The vertex CLI).

For real-project style examples, a common convention is to keep an anon-scripts/ folder with one .apex file per public entry point:

my-project/
├── src/
│ └── hello.vtx # pub fn run()
└── anon-scripts/
└── hello.apex # Hello.vtx_run();

Then:

$ sf apex run --target-org <alias> --file anon-scripts/hello.apex

This is not enforced; it is just a tidy way to invoke your entry points against the org.

vertex build writes to whatever directory out in vertex.jsonc points at, relative to the project root. The default is force-app/main/vertex/classes/. For sf project deploy start to pick the output up, the path needs to be covered by a packageDirectories entry in sfdx-project.json. A standard Salesforce DX project with force-app as its first package directory has that covered automatically.

If you want Vertex output to live in its own package directory (separate from hand-written Apex), add it to sfdx-project.json:

{
"packageDirectories": [
{ "path": "force-app", "default": true },
{ "path": "force-app-vertex" }
],
"sourceApiVersion": "66.0"
}

Then set out to force-app-vertex/main/default/classes in vertex.jsonc.