Choose Backend, Web, Mobile, or Desktop for the tools your team uses. Backend includes trading services, FCM clearing and back-office, and web services.
By surface
Trading path backend
- Language: Scala 2.13 on JDK 21
- Deploy: Kubernetes on GKE with Kustomize + Flux
- Deploy POC: NinjaTrader is testing Argo CD, which Kraken/Payward uses widely.
- Related standards: architecture and CI/CD
Non-trading path backends
- FCM clearing and back-office: Python
- Web services: TypeScript; see Web backends below
- Event-driven deploy: Cloud Run
- Related standards: architecture
FCM clearing and back-office services stay on Python.
Web backends
A web backend serves HTTP to our clients and to partners, and sits off the trading path. Start a new one from this stack.
- Language: TypeScript on Node.js LTS
- Framework: NestJS on Fastify, through
@nestjs/platform-fastify - API contract:
@nestjs/swaggergenerates the OpenAPI document. See architecture. - Data access: Prisma against PostgreSQL on Cloud SQL, at the latest version Cloud SQL supports
- Deploy: Kubernetes on GKE with Kustomize + Flux
- Related standards: architecture, code ownership, and CI/CD
Choose Express only when a dependency requires it, and record that under exceptions.
Repository layout. A web backend ships from the same repository as the client it serves when that client belongs to the same product. Use pnpm workspaces:
apps/
api/ # NestJS service, deploys to GKE
web/ # product client, deploys to Cloudflare Pages
worker/ # long-running processes, deploys to GKE; add when needed
packages/ # code shared between the apps
cloudflare/ # Pages and Worker configuration
kustomize/ # base and per-environment overlaysEach app deploys on its own, so a change to one does not release the others. Give every app directory its own CODEOWNERS entry. See code ownership.
A client that belongs to the shared trader surface goes to the Web surface instead of into a product repository.
- Language: TypeScript; see Backend for web services
- Framework: React 19+ + Strata; Astro 7+ SSR
- Deploy: Cloudflare Pages + R2
NinjaTrader Forge
Forge runs on macOS, Windows, and Linux.
-
Shell: TypeScript 6+ with Electron 44+, React 19+, and Strata
-
Engine and sidecars: C# on .NET 10+, including the NinjaScript runtime
-
Native transport: Rust for the
@forge/shmemshared-memory addon -
Process communication: gRPC for the control plane; shared memory for the hot data path
-
Build and packaging: electron-vite + electron-builder, with macOS DMG, Windows NSIS, and Linux AppImage targets Check the repository for exact versions and build settings:
NinjaTrader 8
Platform-wide
| Concern | Standard |
|---|---|
| Source control | GitHub |
| Build & CI | GitHub Actions on self-hosted runners; reusable actions from NT-NinjaTrader/gh-actions. See CI/CD. |
| CI to cloud auth | Workload Identity, no long-lived keys. See security. |
| Operating systems | Windows, macOS, and Linux; native Windows by default, WSL2 only for a hard dependency. See cross-platform repositories. |
| Containers & registry | Docker to Artifact Registry; build once and promote. |
| Infrastructure | Terraform on GCP (Atlantis on PRs) |
| Secrets | GCP Secret Manager via Workload Identity (external-secrets operator in-cluster). See security. |
| Feature flags | Statsig. See feature flags. |
| Client error tracking | Sentry (web, mobile, desktop) |
| Service error tracking | OpenTelemetry with structured logs, no dedicated tracker. See observability. |
| Telemetry & tracing | OpenTelemetry to Cloud Trace |
| Logs | Cloud Logging (log-based metrics drive alerting) |
| Dashboards & alerts | Cloud Monitoring, defined in Terraform |
| Paging | PagerDuty. See release and incidents. |
| Product analytics | Heap, loaded through Google Tag Manager. See observability. |
| Consent | OneTrust |
| Data warehouse | BigQuery |
| Domain model | Defined once in tradovate/master-scheme, generated downstream. See architecture. |
Version-support policy
+ marks a minimum version. Keep exact versions in repository manifests and lockfiles. Later versions must meet the support policy below.
| Surface | Baseline | Supported versions |
|---|---|---|
| Trading path JVM | JDK 21 only | Build and target JDK 21 |
| Trading path Scala | Scala 2.13 | Stay on 2.13 while the Scala 3 decision is open |
| Non-trading / FCM | Python 3.14+ | Upstream-supported CPython releases. FCM runs on Python 3.11 and plans to migrate to 3.14. |
| Web / services | Node LTS only | Active LTS or Maintenance LTS releases |
| Mobile | Dart / Flutter, current stable | Track upstream stable |
| Desktop / Forge engine | .NET 10+ | SDK floor in engine/global.json; supported .NET LTS releases only |
| Desktop / Forge shell | Electron 44+, React 19+, TypeScript 6+ | Repository manifest and lockfile set exact versions; Electron supplies its own Node runtime |
| Desktop / NinjaTrader 8 | WPF / NinjaScript | Follow the product’s project files and supported Windows runtime; Forge’s .NET baseline does not apply |
Build with JDK 21 LTS and set the compiler target to 21:
// build.sbt, the version floor is enforced, not documented
ThisBuild / scalaVersion := "2.13.14"
ThisBuild / javacOptions ++= Seq("--release", "21")
ThisBuild / scalacOptions ++= Seq("-release:21", "-Werror", "-Wunused:all", "-deprecation")Quality-tooling baseline
Run these checks in CI as part of the quality gates.
| Surface | Format | Lint / static analysis | Types |
|---|---|---|---|
| Scala | scalafmt | scalafix | compiler -Werror |
| Python | ruff format | ruff | mypy |
| TypeScript | Prettier | ESLint | tsc strict |
| Dart | dart format |
dart analyze |
built-in |
| C# | dotnet format |
Roslyn analyzers | built-in |
| Go | gofmt |
go vet + staticcheck |
compiler |
| Rust | rustfmt |
Clippy | compiler |
Run locally the same checks that CI runs:
sbt scalafmtCheckAll compile # compile carries -Werrorruff format --check . && ruff check . && mypy .pnpm prettier --check . && pnpm eslint . && pnpm tsc --noEmitdart format --set-exit-if-changed . && dart analyzedotnet format --verify-no-changes && dotnet buildgofmt -l . && go vet ./... && staticcheck ./...cargo fmt --check && cargo clippy -- -D warnings && cargo buildBuild and dependency management
Use the build and dependency managers below.
| Surface | Build / dependency manager |
|---|---|
| Scala | sbt + coursier |
| Python | uv |
| TypeScript | pnpm |
| Dart | pub |
| C# | NuGet |
| Go | Go modules |
| Rust | Cargo |
Forge uses npm with package-lock.json in shell/frontend, rather than pnpm. Its C# projects use NuGet; the native addon uses Cargo. Run builds and checks through Forge’s repository scripts.
FCM uses pip, with pyproject.toml and == pins for direct dependencies, and does not commit a lockfile. FCM plans to adopt uv.
Commit each project’s lockfile and pin direct dependencies. Use Renovate for dependency updates:
// renovate.json, org-wide dependency currency policy
{
"extends": ["config:recommended"],
"lockFileMaintenance": { "enabled": true },
"vulnerabilityAlerts": { "labels": ["security"] }
}Supply chain
Build once and promote the same artifact through each environment. See The Twelve-Factor App for build/release/run separation and the Artifact Registry docs for registry configuration.
- Generate an SBOM at build time and retain it with the artifact.
- Scan dependencies with Renovate or Dependabot; treat vulnerability alerts as work.
- Sign images and record build provenance so a promoted digest is verifiable downstream.
Governance
Every change to Engineering Standards requires a pull request and review from the Engineering Navigators.
| Rule | Standard |
|---|---|
| Ownership | @NT-NinjaTrader/Engineering-Navigators owns all Engineering Standards pages and reviews them regularly. |
| Amendments | To change an existing standard, open a pull request with an ADR that records the decision and its context, then request review from the Engineering Navigators. |
| New languages and tools | To add a language or tool, follow the exceptions process before adding it to this page. |
| Shared CI | Reuse the shared actions in NT-NinjaTrader/gh-actions; do not re-implement the CI toolchain in individual repositories. |
| Domain model | Define shared domain entities once in tradovate/master-scheme and generate them downstream. Do not redefine them in a service. |
See the Changelog for standards updates.