Skip to main content

Best Practices

Usage recommendations for the Nukk platform, drawn from the capabilities documented in each area. The goal is to help decide when to use what — Flow, Backend App, Frontend App, Add-on, ZTNA, Secret, Config Map, MCP — instead of just listing isolated features.

1. Secrets and Config Maps

  • Never put a credential in plain text inside a Flow, Backend App, or Frontend App. If the value is sensitive (database password, API token, signing key, connection string with an embedded credential), it belongs in a Secret — the value stays masked even after it's saved.
  • If the value is just environment-specific configuration but isn't sensitive (a service URL, a hostname, a feature flag), use a Config Map instead — don't create a Secret just to avoid hardcoding; that hides information that could be freely inspected and makes debugging harder.
  • Practical rule: if the value could be shown in plain text without risk, it's a Config Map; if it grants access to something, it's a Secret.
  • Always explicitly bind the Secret/Config Map to the Flow/App that will use it, in the corresponding tab — the Secret existing on the platform isn't enough; it needs to be selected by the consumer.
  • Use different properties per environment (test, production) within the same Secret/Config Map (e.g. HOST, PASSWORD) instead of creating one Secret per environment — this keeps the same expression ({$.env.name.property}) working in any environment without changing the Flow/App's code.
  • Name Secrets and Config Maps so their purpose is obvious (db-credentials, db-config) — it makes it easier to audit who uses what.

2. API Management

  • Treat the API Gateway as the single entry point for APIs — don't create alternative direct exposure paths for a Backend App or Flow beyond what's necessary; centralizing on Routes makes security, rate limiting, and observability easier.
  • Every API going to production should have Security Type = API Key (or equivalent), with a dedicated Consumer per integration/client — avoid reusing the same Consumer for multiple systems, so you can revoke or limit one consumer's access without affecting the others.
  • Configure rate limits (per second and per minute) that match the backend's real capacity — a Consumer with no limit can bring down a downstream Flow/App in case of misuse or a bug on the client side.
  • Adjust timeouts (read/send/connect) to the integration's real behavior — leaving the ~60s default on every route hides slowness; fast routes should have more aggressive timeouts to fail fast, and integrations that are inherently slow need larger timeouts so valid responses aren't cut off.
  • Only create a Route when the intent is to actually expose the API to the final consumer — internal Flows and Backend Apps that only talk to each other don't need a public Route.

3. When to use a Flow (integration and automation)

Use a Flow when the problem is essentially orchestrating calls between systems — querying a database, calling an external API, transforming a payload, sending a notification, reacting to an event or a schedule. It's the right place for:

  • Integrations with CRMs, ERPs, cloud providers, databases, messaging — the connector catalog already handles authentication, serialization, and retries, so the integration work is just configuring fields, not writing low-level code.
  • Automations triggered by Scheduler, webhook (HTTP), event (Event Consumer), or message (WhatsApp Trigger) — any process that "happens when X occurs," without needing its own interface.
  • Logic that benefits from AI inside the flow itself (the AI Agent component) — interpreting free-form text, summarizing documents, dynamically deciding between multiple sub-tasks.

Don't force a Flow to become a full application. If the need is a rich user interface, or complex domain logic with many business rules versioned as code, consider a Backend/Frontend App and use the Flow only for the integration/orchestration part.

Best practices within the Flow:

  • Always configure error paths (executionOnError) on critical connectors — a Flow with no error handling either fails silently or brings down the whole execution because of a one-off issue in an external system.
  • Split into modules as the Flow grows — isolate reusable business logic from the part that's just the trigger/exposure (API, Scheduler), so the same logic can be reused from different triggers without duplicating connectors.
  • Use the FlowSpec (JSON) to review the full configuration before publishing an important change, especially in flows with many chained connectors.
  • After the build, only configure a Route in API Management if the Flow really needs to be called from outside — Flows triggered by Scheduler or Event Consumer usually don't need any route at all.

4. Backend Apps vs. Frontend Apps

  • Use a Backend App for APIs and workers with their own domain logic, versioned as code (not as visual configuration) — especially when the logic is too complex to comfortably fit in a Flow, or when the team already has an existing service to import via GitHub.
  • Use a Frontend App for screens, dashboards, and pages — publishing is more straightforward (build + deploy already generates a public link), with no need for a Route in API Management.
  • In both cases, a correct Dockerfile is mandatory when importing from GitHub — validate locally that the image builds and comes up on the configured port before importing, so you don't discover the problem only during the platform's build. When creating via vibe code, the platform already handles this — prefer that path when there's no need to bring in an existing repository.
  • Backend App: if the stack is Java Quarkus, configure it correctly to get the Swagger preview for free — it's the fastest way to validate API contracts during development. After deploying, remember to configure the Route in API Management if the API should be public — this step is easy to forget and is a common cause of "the API is deployed but doesn't respond from outside."
  • Frontend App: use the Preview (live preview) to validate the interface before each build, and the AI Copilot to speed up repetitive tasks (error handling, refactor, tests) directly in the app's IDE.
  • Bind Secrets/Config Maps per environment from the start (e.g., a different API URL in test and production) — this avoids hardcoded URLs/configuration that only shows up as a bug when promoting to production.

5. Think Add-ons before building infrastructure yourself

Before manually standing up a database, a cache, or an authentication layer inside a Backend/Frontend App, check whether an Add-on already solves it:

  • Need authentication/SSO/OAuth2? Use the FusionAuth add-on instead of building login from scratch.
  • Need a relational database? Use the PostgreSQL add-on — it already comes with configurable automatic backups, so you don't have to build a backup routine manually.
  • Need cache, session storage, or in-memory pub/sub? Use the Cache (Valkey) add-on, choosing the Persistence Mode based on the real need (disposable pure cache vs. data that needs to survive a restart).

This reduces setup time, centralizes infrastructure patching/maintenance on the platform, and keeps the Backend/Frontend App focused only on application logic.

When to use Cloudflare ZTNA

Use the Cloudflare ZTNA add-on when you need to expose a Flow, App, or another Add-on without opening ports in the environment and without relying on a traditional public Route in API Management — for example, to give access to an internal admin panel, to a staging environment restricted to a group of users, or to any service that shouldn't be exposed directly on the internet. Prefer API Management when the goal is a public API, with Consumers and rate limiting; prefer ZTNA when the goal is controlled access via Zero Trust, especially for admin interfaces or environments not meant for the general public.

6. Use MCP in your development workflow

Connect your AI assistant (Claude Code, Claude, GitHub Copilot) via MCP from the start of a project, not only after a problem has already happened:

  • Ask the assistant to check the Secrets and Config Maps bound to a Flow/App before investigating a configuration bug — it's faster than navigating the platform manually.
  • Use the assistant to deploy a Flow, deploy an app, or inspect Routes/Consumers right from the conversation, keeping code and infrastructure context in the same place.
  • Take advantage of observability queries (logs, metrics) via MCP to speed up debugging without switching screens for every hypothesis.
  • Remember that no delete operation is exposed via MCP — it's safe for diagnostics and constructive actions, but resource removal still needs to be done manually on the platform.

7. Observability and cost — a habit, not an exception

  • Set up Monitoring and check Top Errored Executions regularly, not just when a user complains — problems usually show up in monitoring before they become an incident.
  • Use Trace to understand exactly which step a slow or failing execution is spending time on, instead of guessing from external behavior.
  • Track Usage by environment and by resource type — comparing Test with Production, and separating infrastructure cost from AI token cost, helps quickly identify whether a resource is oversized or whether AI spend is healthy.