Skip to main content

Configuration

When the juno command is run from your terminal or used in a CI environment, it will automatically attempt to locate a config file named juno.config.ts or juno.config.js or juno.config.json within your project's root directory.

The Juno config file defines the settings and options needed for managing and deploying your satellites and other project modules, ensuring consistency across environments.

A basic config file looks like this:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "build"
},
orbiter: {
id: "eeeee-fffff-ddddd-11111-cai"
}
});

At the top level, the Juno configuration includes two main sections:

  1. satellite (required): This defines the behavior of your satellite.
  2. orbiter (optional): This is useful to automatically map your analytics in your application.

Satellite Configuration

Satellites are the core component of your application in Juno. The satellite configuration defines how the satellite operates, including its identifier, datastore, storage, authentication, and more. This configuration is crucial for managing the satellite’s behavior and deploying it across different environments.

The satellite configuration is defined in your Juno configuration file. Below is a detailed explanation of how to configure it.

ID or IDs

Each satellite must be uniquely identified using either:

  • id: A single identifier for the satellite.
  • ids: A mapping of identifiers for multiple environments, such as staging or production.

You can use one of these options but not both simultaneously. See the Environments - Multiple Satellites chapter below for details on setting up multiple ids.

tip

If you are using a framework like Next.js or Vite, Juno provides plugins to simplify loading Satellite and Orbiter IDs from your configuration file. These plugins automatically handle environment variable management and initialization.

Source

The source field specifies the directory containing the built assets for your satellite. This is typically the output directory of your build process, such as /dist or /build, created after running a command like npm run build.

Juno uses this directory to locate the files that will be deployed as part of your satellite. Ensure that this directory includes all the necessary assets, such as HTML, JavaScript, CSS, and any other static or dynamic resources your application requires.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist"
}
});

Ignore files

The ignore attribute allows you to exclude certain files from being deployed to your satellite.

This attribute works similarly to Git's .gitignore, and you can specify which files to ignore using globs.

Here is an example of how the ignore attribute can be utilized:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
ignore: ["**/*.txt", ".tmp/"]
}
});

GZIP

When deploying your application, the CLI automatically searches for JavaScript (js), ES Module (mjs), and CSS (css) files in the source folder and optimizes them using Gzip compression. This is useful because neither the protocol nor a satellite can compress these files, ensuring the best web performance.

If you wish to customize this behavior, you have the option to disable it or provide a different file matching pattern using glob syntax.

To opt-out of Gzip compression, simply set the gzip option to false in your configuration:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
gzip: false
}
});

If you want to customize the default pattern **/*.+(css|js|mjs) to better suit your needs, you can specify your own pattern. For example:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
gzip: "**/*.jpg"
}
});

Encoding

When deploying, the CLI automatically maps the encoding type based on the file extension. The encoding information is then used in the satellite to provide the appropriate HTTP response header Content-Encoding.

The default mappings are as follows:

  • .Z = compress
  • .gz = gzip
  • .br = br
  • .zlib = deflate
  • rest = identity (no compression)

You can also customize the encoding behavior by using the "encoding" attribute in the configuration file.

This attribute works similarly to Git's .gitignore, and you can specify which files to ignore using globs.

Here is an example of how the "encoding" attribute can be utilized:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
encoding: [["**/releases/*.gz", "identity"]]
}
});

Predeploy

The predeploy option allows you to define a list of scripts or commands to be executed before the deployment process begins. This is particularly useful for automating tasks such as:

  • Compiling assets.
  • Running tests or linters.
  • Preparing production-ready files.

These scripts are executed sequentially in the order they are listed.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
predeploy: ["npm run build", "npm run lint"]
}
});

Postdeploy

The postdeploy option allows you to define a list of scripts or commands to be executed after the deployment process completes. This can be used for various follow-up tasks, such as:

  • Sending notifications or alerts to administrators.
  • Cleaning up temporary files.
  • Logging deployment information for auditing.

Like predeploy, these scripts are executed sequentially in the order they are listed.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
postdeploy: ["./scripts/notify-admins.sh", "echo 'Deployment complete'"]
}
});

Storage

The storage configuration accepts the following options and parameters:

HTTP Headers

Headers allow the client and the satellite to pass additional information along with a request or a response. Some sets of headers can affect how the browser handles the page and its content.

For instance, you may want to set a specific Cache-Control for performance reasons.

Here's an example of the headers object:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
storage: {
headers: [
{
source: "/",
headers: [["Cache-Control", "public,max-age=0,must-revalidate"]]
},
{
source: "assets/fonts/*",
headers: [["Cache-Control", "max-age=31536000"]]
},
{
source: "**/*.jpg",
headers: [
["Cache-Control", "max-age=31536000"],
["Access-Control-Allow-Origin", "*"]
]
}
]
}
}
});

This source attribute works similarly to Git's .gitignore, and you can specify which files match the headers using globs.

The headers is an array of objects, each containing key and value, and these apply to the matching paths.

note
  • The Content-Type header is calculated automatically and cannot be altered.
  • No validation or check for uniqueness is performed. For example, if a header matches a file based on multiple rules, multiple headers will be set.
  • Likewise, if you provide the same header when you upload file to your "Storage" and within the configuration, both headers will be set in the response.

Rewrites

You can utilize optional rewrites to display the same content for multiple URLs. Rewrites are especially useful when combined with pattern matching, allowing acceptance of any URL that matches the pattern.

Here's the basic structure for a rewrites attribute.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
storage: {
rewrites: [
{
source: "/hello/**",
destination: "/hello/world.html"
}
]
}
}
});

This source attribute works similarly to Git's .gitignore, and you can specify which files match the rewrites using globs.

note
  • Rewrites are only applied to requests that do not match any existing resources.
  • By default, all unknown paths are automatically rewritten to /index.html (or /404.html if you provide such a page). You cannot disable this default behavior.

Redirects

Use a URL redirect to prevent broken links if you've moved a page or to shorten URLs. For example, you could redirect a browser from juno.build/start-building to juno.build/get-started.html.

Here's the basic structure for a redirects attribute.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
storage: {
redirects: [
{
source: "/hello",
location: "/world/index.html",
code: 301
}
]
}
}
});

The redirects attribute contains an array of redirect rules:

FieldDescription
sourceThis source attribute works similarly to Git's .gitignore, and you can specify which files match the redirects using globs.
locationA relative path to where the browser should make a new request.
codeThe HTTPS response code. Use a type of 301 for 'Moved Permanently' or 302 for 'Found' (Temporary Redirect).

iframe

For security reasons and to prevent click-jacking attacks, dapps deployed with Juno are, by default, set to deny embedding in other sites.

You can customize this behavior by setting the iframe option to either same-origin, which restricts your pages to be displayed only if all ancestor frames have the same origin as the page itself, or allow-any, which allows your project to be embeddable by any site.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
storage: {
iframe: "same-origin"
}
}
});

Maximum Memory Size

You can configure optional limits on heap and stable memory for your smart contract to control the creation and update of assets in your storage.

When the limit is reached, the Storage and smart contract will continue to operate normally but will reject the upload of new assets.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
storage: {
maxMemorySize: {
stable: 1_073_741_824n // For example max. 1 GiB in bytes of Stable memory
}
}
}
});

Datastore

The datastore configuration accepts the following options and parameters:

Maximum Memory Size

You can configure optional limits on heap and stable memory for your smart contract to control the creation and update of documentations in your Datastore.

When the limit is reached, the Datastore and smart contract will continue to operate normally but will reject changes to documents.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
datastore: {
maxMemorySize: {
stable: 1_073_741_824n // For example max. 1 GiB in bytes of Stable memory
}
}
}
});

Authentication

The authentication configuration accepts the following options and parameters:

Derivation origin

The behavior of Internet Identity can be customized to ensure that users are recognized consistently across different domains or subdomains of your application.

For example, if you set derivationOrigin to "hello.com", a user signing in at https://hello.com will receive the same identifier (principal) as when signing in at https://www.hello.com.

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
authentication: {
internetIdentity: {
derivationOrigin: "hello.com"
}
}
}
});

Assertions

The CLI conducts several assertions when interacting with your Satellite, one of which involves monitoring the heap memory size. Typically, the CLI checks to ensure that the heap memory does not exceed the 1 GB limit before deployment. For instance, if your heap memory usage is close to 900 MB, the CLI will prompt you to confirm the deployment.

You can customize this behavior by adjusting the heap memory limit in bytes. For example, to set a new limit of 678 MB, update your configuration as follows:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
assertions: {
heapMemory: 678000000
}
}
});

Alternatively, these checks can be completely disabled. To do so, set the heapMemory assertion to false:

import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
source: "dist",
assertions: {
heapMemory: false
}
}
});

Settings

The settings field allows you to configure various aspects of the module’s behavior and resource usage, such as memory limits, compute allocation, and log visibility.

Overview:

  • Freezing Threshold: Prevents the module from being deleted by pausing operations when cycles drop below a certain level.
  • Reserved Cycles Limit: Ensures a minimum number of cycles are available for future operations.
  • Log Visibility: Controls who can access the module’s logs.
  • Heap Memory Limit: Sets the hard maximum heap memory available to the module.
  • Memory Allocation: Pre-allocates memory for optimized performance.
  • Compute Allocation: Reserves a percentage of the subnet’s compute resources.
import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
id: "qsgjb-riaaa-aaaaa-aaaga-cai",
settings: {
freezingThreshold: 2_592_000n,
reservedCyclesLimit: 5_000_000_000_000n,
logVisibility: "controllers",
heapMemoryLimit: 2048n,
memoryAllocation: 1_073_741_824n,
computeAllocation: 50n
}
}
});

For a complete explanation of all settings, including detailed examples and calculations, see the Settings section.


Orbiter Configuration

Orbiters are an optional component of your application used for analytics.

ID

An orbiter has a unique identifier (id). This ID is used to reference the orbiter during operations and deployments.

tip

If you are using a framework like Next.js or Vite, Juno provides plugins to simplify loading Satellite and Orbiter IDs from your configuration file. These plugins automatically handle environment variable management and initialization.


Apply Changes

Configurations such as above storage, datastore, authentication, and settings require explicit application to your smart contract as they directly impact its behavior.

To apply your changes, run the juno config command in the CLI after modifying your configuration file.


Intellisense

To enable intellisense in your IDE for TypeScript or JavaScript configurations, you will need to install the necessary types:

npm install @junobuild/config --save-dev

Afterwards, you can leverage your IDE's intellisense with jsdoc type hints:

juno.config.js
/** @type {import('@junobuild/config').JunoConfig} */
export default {
// ...
};

Alternatively, you can use the defineConfig helper which should provide intellisense without the need for jsdoc annotations:

juno.config.js
import { defineConfig } from "@junobuild/config";

export default defineConfig({
// ...
});

Conditional Config

If the config needs to conditionally determine options based the mode being used, it can export a function instead:

juno.config.js
import { defineConfig } from "@junobuild/config";

export default defineConfig(({ mode }) => ({
satellite: {
id: "aaaaa-bbbbb-ccccc-ddddd-cai",
source: "dist",
...(mode === "production" && { iframe: true })
}
}));

Modes

By default, the CLI runs command for the production mode.

This means when running a juno command in your terminal, it will pass the mode production to read your configuration.

You can overwrite the default mode used for a command by passing the --mode option flag. For example, if you want to deploy your app for a staging mode:

juno deploy --mode staging

Environments - Multiple satellites

You may wish to deploy or operate a similar project across various environments. For instance, deploying the same application on multiple satellites can be accomplished by utilizing modes.

To accommodate different satellite IDs, you can use a conditional config:

juno.config.js
import { defineConfig } from "@junobuild/config";

export default defineConfig(({ mode }) => ({
satellite: {
id:
mode === "staging"
? "11111-22222-33333-44444-cai"
: "aaaaa-bbbbb-ccccc-ddddd-cai",
source: "dist"
}
}));

Or explicitly list the IDs:

juno.config.js
import { defineConfig } from "@junobuild/config";

export default defineConfig({
satellite: {
ids: {
staging: "11111-22222-33333-44444-cai",
production: "aaaaa-bbbbb-ccccc-ddddd-cai"
},
source: "dist"
}
});

The latter method is also compatible with JSON configuration:

juno.config.json
{
"satellite": {
"ids": {
"staging": "11111-22222-33333-44444-cai",
"production": "aaaaa-bbbbb-ccccc-ddddd-cai"
},
"source": "dist"
}
}

Note that defining an id or at least a production entry in ids is mandatory.