Nodaro Docs
DocumentationNode ReferenceModelsAI Agents (MCP)DevelopersSelf-hostingResearch

Editions and surface profiles

Compare the Community, Business and Cloud editions, switch a self-hosted Nodaro to Business, and narrow its interface with a NODARO_SURFACE_PROFILE.

Nodaro has three editions — Community, Business and Cloud — built from the same code and selected with the EDITION variable. On the Business edition, a surface profile then narrows what the install shows, without a rebuild. It can hide parts of the interface, remove nodes and models, rename the product and restrict sign-in. This page covers both.

The three editions

CommunityBusinessCloud
Self-hostableYesYesNo, managed by Nodaro
Admin panelNoYesYes
User managementNoYesYes
Credit ledgerNoNoYes
BillingNoNoYes
Credit prices set by adminsNoNoYes
Surface profileIgnoredYesYes
  • Community (EDITION=community, the default) is the free self-hosted edition. Anyone who signs up becomes a regular user.
  • Business (EDITION=business) adds the admin panel and user management. It is still self-hosted and still has no billing.
  • Cloud (EDITION=cloud) adds credits and billing. It powers app.nodaro.ai and is not meant for self-hosting.

The Business edition's admin panel and user management are Enterprise features. You may run them for development and testing, but using them in production requires a Nodaro Enterprise subscription. See License.

Switch a self-hosted install to Business

The API reads EDITION at startup. The editor in the browser reads its edition from VITE_EDITION when the image is built. The published image is built as the Community Edition, so a Business install is built from source.

Moving from Community to Business has no database cost: the schema is the same.

Change both values in the compose file

In docker-compose.community.yml, under the nodaro service, change the two lines that say community:

  nodaro:
    build:
      args:
        VITE_EDITION: business      # was: community
    environment:
      EDITION: business             # was: community

Both lines are fixed in the compose file, so setting EDITION in .env has no effect.

Build and start

docker compose -f docker-compose.community.yml build --no-cache nodaro
docker compose -f docker-compose.community.yml up -d

Update a source-built install with git pull and build. docker compose pull would download the published Community image again.

The build refuses an empty or unknown VITE_EDITION. Without that check, an unset value would build cleanly and fall back to community, and a Business image would ship without its admin panel. The compose file passes the value for you. A hand-written docker build needs --build-arg VITE_EDITION=community, business or cloud.

What is fixed at build time and what is not

Three browser settings are not fixed at build time: the API address, the browser's sign-in address and the anon key. At boot, the container writes them into /config.js from PUBLIC_URL, FRONTEND_SUPABASE_URL and SUPABASE_ANON_KEY, and the browser reads that file before the app starts. So the published image serves any port or domain after a restart. The VITE_* build arguments are only fallbacks for unset runtime values.

Other build-time browser settings:

Build argumentWhat it doesDefault
VITE_STUDIO_URLThe address of the Studio app, for Open in Studio linkshttps://studio.nodaro.ai
VITE_PERSON_URLThe address of the Person app, for the Open Person card on the home screenhttps://person.nodaro.ai

Surface profiles

NODARO_SURFACE_PROFILE narrows the interface of a Business or Cloud install without a rebuild. The Community Edition ignores it and always shows the full interface.

  • Format. Inline JSON, or @/path/to/profile.json to read a file. To use a file on the compose stack, mount it into the container and give its path inside the container.
  • Narrow only. A profile can hide and remove. It never enables something that the edition disables.
  • Every field is optional. An empty list means "keep the default". Unset, the install shows the full interface.
  • Errors. A malformed field falls back to that field's default, with a warning in the log. A profile that does not load at all stops a Business or Cloud install from booting, with [surface-profile] FATAL … Refusing to boot a narrowing deployment mainline-open. That happens with an unreadable file, invalid JSON, or a value that fails validation as a whole. A narrowing install must never come up showing everything.
  • Apply. Restart the app. The profile reaches the browser through /config.js.

Example

NODARO_SURFACE_PROFILE={"nav":{"hide":["gallery"]},"brand":{"productName":"Studio"},"outputs":{"allowPublic":false},"voice":{"allowedGenders":["male"]}}

This hides the gallery, renames the product to Studio, keeps every output private and offers male voices only.

Fields

FieldWhat it does
nav.hideHides sidebar entries. Values: gallery, explore, pricing, templates, apps, community, integrations.
dashboard.tabsOne ordered whitelist of the home screen's sections. See Home-screen sections.
nodes.deny, models.denyNode types and model IDs to remove everywhere: the node picker, GET /v1/nodes, GET /v1/models, the MCP tools, and at run time. A removed node fails with node_not_available.
nodes.allow, models.allowWhitelists. When a list is not empty, only the listed node types or model IDs are offered, and deny still subtracts from them. See Allow lists.
auth.methods, auth.ssoLabelThe sign-in methods to offer: email, google, sso. sso is dropped unless auth.ssoLabel is set. See Sign-in methods.
siblings.appsReplaces the Nodaro links in the product switcher: [{ "label": "...", "url": "..." }].
brand.productNameReplaces the wordmark and the page title. Absent, the page title stays as shipped.
brand.wordmarkShort text shown beside your own logo in the sidebar header, for an install that ships its own logo files. For example, product name Acme Studio with wordmark Studio.
brand.descriptionReplaces the page's meta description.
brand.platformLinksfalse hides the platform's own legal, documentation, release-note and product-promotion links. Links you set in siblings.apps stay.
locale.defaultThe language a new visitor starts in.
locale.pickerfalse hides the language picker. The default is true.
outputs.allowPublicfalse makes every output private, whatever the user chooses.
voice.allowedGendersRestricts voices to any subset of male, female and neutral. Empty means every gender. See Voice genders.
features.hideSwitches whole features off: copilot removes the Workflow Copilot, and presentation hides the canvas Present tab.
catalogs{ "required": true, "factoryPresets": false } for installs that need reviewed picker content. See Picker catalogs.

Logos and the favicon are not part of the profile. Replace them with a layer of static files in your Docker image.

Home-screen sections

dashboard.tabs is one ordered whitelist. The full key set is workflows, projects, apps, miniapps, templates, tutorials, statistics, gallery, studio and mcp.

  • workflows, projects, studio — the lists of the Continue tab's workspace filter, in the order of your list. If your list names none of the three, all three show, so the main list is never blank.
  • apps — the Nodaro apps band on Continue.
  • templates — the "Start from a template" row on Explore, and the Templates sidebar entry.
  • tutorials — the Level up tutorials on Explore, and the Tutorials sidebar entry. Without templates and tutorials, the Explore tab is not shown.
  • miniapps — the MiniApps sidebar entry.
  • statistics — the statistics overview on the Executions page.
  • mcp — the fourth "Jump back in" list: the workflows an MCP client created in its automatic mcp project.

List every section you want to keep. For example, ["workflows","projects","statistics","tutorials"] keeps the workflow and project lists, the tutorials and the statistics. It drops the Studio list, the apps band, the template row and the Templates and MiniApps sidebar entries. nav.hide still applies on top.

Allow lists

An allow list is the safer shape for a curated install. A new node or model then stays unavailable until you list it, instead of appearing because you did not deny it.

  • Utility nodes, such as sticky-note and preview, are never removed by omission from an allow list. Only an explicit deny removes them.
  • Admins can change node and model availability at runtime in the admin panel. A saved runtime setting replaces the profile's lists until it is reset to the factory state.
  • A node that an admin disables in the admin panel stays usable by admins. A node removed by the profile is removed for admins too. But an admin who enables a profile-removed node again in the admin panel releases it to everyone, so give the admin role only to people you trust with that.
  • A disabled model is disabled for admins too.
  • A run is checked as the user it runs as. An app or presentation run executes as the person running it. A scheduled or webhook-triggered run executes as the workflow's owner, and an API token or a connected app acts as its own owner. When that owner is an admin, the run can use a node hidden from users, so treat the webhook URL of such a workflow with care.
  • An app, a component or a template that contains a hidden node cannot be published: the request fails with node_not_available.
  • A change of role reaches these checks within about 5 minutes.

Sign-in methods

auth.methods narrows the sign-in methods on the login page, among email, google and sso. Keep sso in the list only together with auth.ssoLabel, the text of the SSO button.

A list that names only sso also enables a server-side rule: every signed-in account must have been created or linked through single sign-on. Any other session is refused on its first API call with 403 sso_required, so an account registered directly on the sign-in service cannot use the install. Adding email to the list disables the rule. See Single sign-on.

Voice genders

voice.allowedGenders is enforced on the server:

  • The voice list and the shared voice library show only voices of the allowed genders.
  • A request with a built-in voice of another gender is refused with voice_not_available.
  • Every default and fallback voice becomes the first voice of an allowed gender.
  • The editor hides the vocal-gender tags of the other genders in the Suno nodes.

The output gender of the voice-creation nodes cannot be known in advance. To remove them, add "nodes":{"deny":["voice-design","voice-remix"]}.

Picker catalogs

For installs that must offer only reviewed picker content, set "catalogs":{"required":true,"factoryPresets":false}.

  • With required: true, the editor offers picker choices only after it receives the complete curated catalog from the server, and offers none if that request fails. New nodes and factory resets use only offered values.
  • With factoryPresets: false, the bundled presets are hidden in the editor and the API. Users' own presets stay.
  • The server also rejects excluded catalog choices in imported or previously saved workflows.

Frequently asked questions

Last updated on

On this page