# Juno > Access keys play a crucial role in granting permissions to Mission Controls, Satellites or Orbiters within Juno. --- # Source: https://juno.build/docs/miscellaneous/access-keys.md # Access Keys Access keys play a crucial role in granting permissions to Mission Controls, Satellites or Orbiters within Juno. When you sign in to Juno's [Console](/docs/terminology.md#console) (for example, with Internet Identity) and create modules, you — and no one else, not even Juno — become their owner. ![Juno's console flow](/assets/images/console-d0903e4989f7c4db5f4e85567211d266.png) **Note:** * What was previously referred to as _controllers_ in earlier versions of the documentation is now called _administrative access keys_. The concept remains the same — only the terminology has been updated for clarity and consistency. * One access key is identified by a [principal](/docs/terminology.md#principal). --- ## Roles Each access key is assigned a **role** that defines what it can do: | Role (Internal) | Display Name | Can Submit | Can Apply/Commit | Can Deploy Immediately | Can Upgrade Immediately | | --- | --- | --- | --- | --- | --- | | **Admin** | Administrator | ✅ | ✅ | ✅ | ✅ | | **Write** | Editor | ✅ | ✅ | ✅ | ❌ | | **Submit** | Submitter | ✅ | ❌ | ❌ | ❌ | An **administrator** can perform tasks such as configuring or deploying an app, topping up a module, creating a new collection in the [datastore](/docs/build/datastore.md) or [storage](/docs/build/storage.md), or configuring a custom domain in the [hosting](/docs/build/hosting.md). An **editor** can publish new serverless function versions to a Satellite’s CDN, deploy your frontend application, and read data from a collection. However, it cannot directly upgrade a Satellite or start/stop a module. A **submitter** can propose changes—such as publishing a new version of a serverless function or frontend app—but those changes must be manually reviewed and applied using the Console UI or CLI. --- ## Generating Access Keys You can generate additional access keys to allow other developers, services, or CI pipelines to interact with your modules. When doing so, you can assign a role based on the level of access required. Access keys can be generated either through the Console UI or using the CLI. **Note:** You can generate a limited number of administrator access keys for a single module, in line with the limitation set by the [Internet Computer](https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-create_canister). To accomplish this, you have two main options. **Tip:** When creating a new Satellite, it’s very likely that you’ll want to generate access keys for local development or to enable automated deployments from CI. Check out the guides: * [GitHub Actions](/docs/guides/github-actions.md) * [Manual Deployments](/docs/guides/manual-deployment.md) --- ## Generate an Access Key with the Console UI You can generate and manage access keys through the Console: 1. Go to [http://console.juno.build](http://console.juno.build) and select your module (Satellite, Analytics or Mission Control) 2. Open the **Setup** tab 3. Scroll to the **Access Keys** section and click **Add an access key** 4. Choose **Generate a new access key** 5. Select the desired role (e.g., **Administrator**) 6. Click **Submit** You can also manually enter an access key instead of generating one, if you wish to reuse an existing one. --- ## Generate an Access Key with the CLI When using the CLI, you can either reuse an existing access key or generate a new one. --- ### Reuse an existing access key When setting up an additional Satellite, you might want to reuse an existing access key already configured on your local machine. To do this, simply run: ``` juno login ``` and follow the instructions. When you run the command, the CLI checks if an access key is already present on your machine. If found, it will give you the option to either reuse the existing key or generate a new one. If you choose to reuse it, the CLI will guide you through the process. --- ### Generate a new access key To **generate a new access key** and attach it to your desired module, you can run: ``` juno login ``` The CLI will guide you through the process. This method is useful if you want to generate a completely new key and apply it across all your modules. **Note:** This action will overwrite the previously saved key used to configure your local CLI environment. --- # Source: https://juno.build/docs/guides/ai.md # Using Juno with AI If you're using AI to build with Juno, you can use our `llms.txt` files to help AI tools better understand the platform. --- ## LLMs.txt An [LLMs.txt](https://llmstxt.org/) file is a plain text file that provides instructions or metadata for large language models (LLMs). It often specifies how LLMs should process or interact with content. It's similar to a `robots.txt` or `sitemap.xml` file, but tailored for AI models. --- ### Available routes We provide several `llms.txt` routes. * [`llms.txt`](/llms.txt): Table of contents with links to individual Markdown docs * [`llms-full.txt`](/llms-full.txt): Entire documentation in a single Markdown file Most AI tools work best with one of these formats. Some tools (like Cursor) can benefit from indexing both. Use the combination that works best with your workflow. ### How to use it Here are some examples of how the `llms.txt` files can be used with AI tools. **Note:** 🙏 Help us improve! If you use a tool that supports LLMs.txt files, [open a pull request](https://github.com/junobuild/docs/edit/main/docs/guides/ai.md) to add your example to this page. ### Cursor You can use custom documentation in Cursor's context using the `@Docs` feature. #### Setup To add custom documentation, type `@Docs` and select **Add new doc**, or go to `Cursor Settings` > `Features` > `Docs`. Add both `llms.txt` URLs: | Name | Entry point | | --- | --- | | Juno | [llms.txt](https://juno.build/llms.txt) | | Juno (full) | [llms-full.txt](https://juno.build/llms-full.txt) | Cursor will index all subpages and use both files to improve context and coverage. #### Usage Type `@Docs` in chat to view available docs and select the Juno entries to begin using the references. **Important:** You must reference the Juno docs in chat using `@Docs` — Cursor won't use them otherwise. For example, you could start a conversation with: _I want to create a web shop app with Next.js using @Juno and @Juno (full)._ #### Resources Read more in the [Cursor documentation](https://docs.cursor.com/context/@-symbols/@-docs). --- # Source: https://juno.build/docs/guides/angular.md # Source: https://juno.build/docs/examples/frontend/angular.md # Angular Example This project is a note-taking app template built with **Angular**, **TypeScript**, and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template angular-example ``` Source: [github.com/junobuild/create-juno/templates/angular-example](https://github.com/junobuild/create-juno/tree/main/templates/angular-example) --- ## Folder Structure ``` angular-example/├── public/ # Static assets├── src/│ ├── app/ # Angular modules, components, services, and types│ ├── environments/ # Environment configuration files│ ├── styles.css # Tailwind CSS styles│ └── main.ts # Angular entry point├── juno.config.mjs # Juno Satellite configuration├── package.json # Project dependencies and scripts├── angular.json # Angular CLI configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **app.component.ts**: Main Angular component, bootstraps the app and layout. * **components/**: Contains UI and logic for authentication, notes table, modal, banner, etc. * **services/**: Angular services for interacting with Juno and managing app state. * **types/note.ts**: TypeScript interface for notes. --- ## Data Structure * **Note** (`src/app/types/note.ts`): ``` export interface Note { text: string; url?: string;} ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `src/environments/environment.ts` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * **juno.config.mjs**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **src/environments/environment.ts**: Contains the Satellite ID for local development. * **src/environments/environment.prod.ts**: Contains the Satellite ID for production. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `src/environments/environment.prod.ts` and `juno.config.mjs` with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in TypeScript and Angular components/services. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/app/app.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/app.component.ts) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/app/services/auth.service.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/services/auth.service.ts) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/app/components/login/login.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/components/login/login.component.ts) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/app/components/logout/logout.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/components/logout/logout.component.ts) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/app/services/docs.service.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/services/docs.service.ts) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/app/components/modal/modal.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/components/modal/modal.component.ts) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/app/components/delete/delete.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/components/delete/delete.component.ts) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/app/components/modal/modal.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/components/modal/modal.component.ts) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/app/components/delete/delete.component.ts`](https://github.com/junobuild/create-juno/blob/main/templates/angular-example/src/app/components/delete/delete.component.ts) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/miscellaneous/architecture.md # Architecture Juno is your own self-contained execution space. Everything your app needs — frontend, backend logic, storage — gets bundled into a single deployable WebAssembly (WASM) container called a Satellite. One artifact. One push. That's your app. No DevOps. No backend boilerplate. No surprise complexity. Juno's architecture is designed to give developers complete control and ownership. It combines familiar developer workflows with an environment that runs independently once deployed — without Juno's intervention. ![Juno architecture schema showing developer control flow](/assets/images/architecture-ea813c74e7ec12ec0989052392308143.png) --- ## How It Works A typical Juno development flow looks like this: 1. **Build your frontend** using Next.js, React, SvelteKit, Vue or any other framework you love (or none). 2. **Add backend logic** (if needed) via serverless functions written in Rust or TypeScript. 3. **Bundle everything into a Satellite** — a single WebAssembly container that holds your entire application, including its logic, state, and storage. 4. **Deploy using the CLI or GitHub Actions.** No servers to configure. No infrastructure to manage. Once deployed, your Satellite runs independently in an unstoppable environment, entirely under your control. --- ## Platform Services Juno provides supporting services to manage your projects, while keeping everything under your ownership: ### Console The Console is a platform for managing your projects. It runs as its own container, combining a user interface with orchestration logic. It provides services such as: * Creating, upgrading, and deleting Satellites. * Managing authentication, storage, data, and application state. * Monitoring logs from serverless functions. * Setting custom domains. * Spinning up and reviewing analytics. You can access the Console at [console.juno.build](https://console.juno.build). **Note:** The Console is not decentralized. It is maintained by Juno to provide a stable management platform and up-to-date developer experience. However, all applications, data, and infrastructure you deploy through it remain under your control. In the future, there is a strong will to resolve this dependency by making the Console self-hostable or governed by a DAO, aligning it with the same principles of ownership and autonomy as the rest of the platform. It is worth noting that Juno is fully open source. Anyone can review its source code at any time. And while not formally documented, the Console is already self-hostable today — offering anyone who wants full control over the entire stack the option to do so. ### Observatory The Observatory is a proxy service used solely for developer notifications. When monitoring is enabled in a developer's Mission Control, events such as automatic top-up successes or failures trigger a message sent through the Observatory to notify the developer via email. This setup ensures that each Mission Control does not need to maintain its own notification infrastructure. The Observatory only forwards messages — it does not monitor, modify, or access any application logic or data. ### CDN Juno maintains a CDN that stores libraries, templates, and pre-built WASM code. These pre-built WASM containers are official module versions shipped by Juno. When a new release is available, it is uploaded to the CDN, allowing developers to upgrade e.g. their Satellites using the latest version. While it functions as a CDN, technically it's not a traditional content delivery network. It is itself a Satellite. --- ## Developer-Owned Spaces Juno's architecture is built on a microservices approach, where each component runs independently as its own WASM container, giving you modular control over your infrastructure. ### Satellites Satellites are your applications. Each one is a self-contained unit that bundles: * Frontend assets * Default backend features * Custom serverless functions * Data and storage * Permissions and access control ### Orbiters Orbiters provide analytics — a decentralized alternative to services like Google Analytics. Orbiters collect traffic, page views, and device information, under your ownership and without exposing user data to third parties. ### Mission Control Mission Control is an optional monitoring service that automatically tracks and maintains your Satellites and Orbiters. When enabled, it monitors [cycles](/docs/terminology.md#cycles) balances across your modules and automatically tops them up when needed, ensuring your applications stay running without manual intervention. --- ## CI/CD and Deployment You can deploy and upgrade your Satellites using GitHub Actions or the Juno CLI. * Deployment automation is opt-in. * Juno does not control or interfere with your deployed app. * Once live, your apps remain running independently. Each Satellite uses a role-based permission system managed via [access keys](/docs/miscellaneous/access-keys.md), letting you decide whether to retain full access, delegate writable access, or allow third parties to solely propose changes. --- ## Libraries, Tools, and Emulator Juno provides many JavaScript libraries, Rust crates, templates and tooling to get started and integrate with your workflow. You can find all the code in the [Juno GitHub organization](https://github.com/junobuild). It also provides an emulator for [local development](/docs/guides/local-development.md) that mimics as closely as possible the experience you get in production. --- # Source: https://juno.build/docs/examples/functions/typescript/assertion.md # Source: https://juno.build/docs/examples/functions/rust/assertion.md # Rust Assertion Example This example demonstrates how to write a **custom assertion** in **Rust** for a Juno **serverless function**. It shows how to intercept and validate data operations—such as rejecting specific content—before it's written to the datastore. The project includes a minimal frontend to help trigger and test the logic, but the primary focus is the backend assertion. You can browse the source code here: [github.com/junobuild/examples/tree/main/functions/rust/assertions](https://github.com/junobuild/examples/tree/main/functions/rust/assertions) --- ## Folder Structure ``` rust/assertions/├── src/│ ├── satellite/ # Rust Satellite serverless function│ │ ├── src/│ │ │ └── lib.rs # Main Rust logic for Satellite│ │ ├── satellite.did # Candid interface definition│ │ └── Cargo.toml # Rust package config├── src/components/ # Minimal frontend React components├── juno.config.ts # Juno Satellite configuration├── package.json # Frontend dependencies└── ... ``` --- ## Key Features * **Custom Assertions in Rust**: Demonstrates how to reject or validate data before it's saved, using Rust serverless functions. * **Serverless Integration**: Runs as a Satellite function and integrates with Juno's datastore and authentication system. * **Minimal UI for Testing**: A simple frontend is included to test and demonstrate the assertion logic in action. --- ## Main Backend Components * **src/satellite/src/lib.rs**: The core Rust logic for the Satellite serverless function. Implements the custom assertions (e.g., only allow certain valid inputs, etc.). * **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function. --- ## Example: Custom Assertion in Rust Here’s the actual Rust logic from `lib.rs`: ``` // This example defines a custom assertion in a Juno Satellite using Rust.// It checks if a document being saved to the "notes" collection contains the word "hello".// If it does, the assertion rejects the operation and logs a message.use ic_cdk::print;use junobuild_macros::assert_set_doc;use junobuild_satellite::{include_satellite, AssertSetDocContext};use junobuild_utils::decode_doc_data;use serde::{Deserialize, Serialize};#[derive(Serialize, Deserialize)]struct Note { text: String, url: Option,}#[assert_set_doc(collections = ["notes"])]fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> { let note = decode_doc_data::(&context.data.data.proposed.data)?; if note.text.to_lowercase().contains("hello") { print(format!("❌ Rejected note containing 'hello': {}", note.text)); return Err("The note should not contain the keyword 'hello'.".to_string()); } print(format!("✅ Note accepted: {}", note.text)); Ok(())}include_satellite!(); ``` **Explanation:** * Defines a `Note` struct with `text` and optional `url` fields. Similar as the fields used in the frontend. * Uses the `#[assert_set_doc]` macro to create a custom assertion for the `notes` collection. * When a note is created or updated, the assertion checks if the note's text contains the word "hello" (case-insensitive). * If it does, the note is rejected and an error message is returned; otherwise, the note is accepted. * Prints a message to the log for both accepted and rejected notes. * `include_satellite!();` brings in the necessary boilerplate for the Juno Satellite runtime. --- ## How to Run 1. **Clone the repo**: ``` git clone https://github.com/junobuild/examplescd rust/assertions ``` 2. **Install dependencies**: ``` npm install ``` 3. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 4. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 5. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 6. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` 7. **Build the serverless functions** (in a separate terminal): ``` juno functions build ``` The emulator will automatically upgrade your Satellite and live reload the changes. --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.ts` with the production Satellite ID. * Build and deploy the frontend: ``` npm run buildjuno hosting deploy ``` * Build and upgrade the serverless functions: ``` juno functions buildjuno functions upgrade ``` --- ## Notes * This example focuses on the Rust serverless function; the frontend is intentionally minimal and only included for demonstration purposes. * Use this project as a starting point for writing custom assertions and backend logic in Rust with Juno. --- ## Real-World Example Want to see how assertions and serverless logic are used in a live project? Check out [proposals.network](https://proposals.network), an open-source app built with Juno: * GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network) * Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs) This app uses: * `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets * Shared helper modules like `assert`, `delete`, and `types` to keep logic organized * A real-world pattern of chaining asset/document deletions with assertions It’s a great reference for more advanced setups and multi-collection coordination. --- ## References * [Serverless Functions Guide](/docs/guides/rust.md) * [Functions Development](/docs/build/functions.md) * [Rust SDK Reference](/docs/reference/functions/rust/sdk.md) * [Rust Utils Reference](/docs/reference/functions/rust/utils.md) * [Run Local Development](/docs/guides/local-development.md) * [CLI Reference](/docs/reference/cli.md) * [Configuration Reference](/docs/reference/configuration.md) * [Datastore Collections](/docs/build/datastore/collections.md) --- ## Crate Docs These crates are used to build and extend serverless functions in Rust with Juno: * [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration. * [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions. * [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling. * [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console. * [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno. --- # Source: https://juno.build/docs/guides/astro.md # Astro Explore how to create a Juno project developed with Astro. [## 📄️ Build Learn how to integrate Juno with Astro. Follow our quickstart guide to set up your development environment, configure your project, and start building with Juno.](/docs/guides/astro/build.md) [## 📄️ Deploy Learn how to deploy your Astro project to Juno. Follow the deployment guide to configure static exports, set up your Satellite, and publish your site to production.](/docs/guides/astro/deploy.md) --- # Source: https://juno.build/docs/guides/vue/build.md # Source: https://juno.build/docs/guides/sveltekit/build.md # Source: https://juno.build/docs/guides/react/build.md # Source: https://juno.build/docs/guides/nextjs/build.md # Source: https://juno.build/docs/guides/astro/build.md # Source: https://juno.build/docs/guides/angular/build.md # Build an Angular App Ready to implement a feature-rich application with Juno? You can choose a step-by-step approach, building each component gradually, or dive into our quickstart template, which showcases Juno's core features. Which path would you like to explore next? ([Step-by-step](#step-by-step))([Quickstart](#quickstart)) --- ## Step-by-step This guide provides quickstart instructions for integrating Juno in two scenarios: starting a new project and adding Juno to an existing Angular app. ### 1\. Choose Your Integration Path You can either start a new project or add Juno to an existing app. ### Path A: Start a new project with a template Create a new project using the Juno quickstart CLI: * npm * yarn * pnpm ``` npm create juno@latest -- --template angular-starter ``` ``` yarn create juno -- --template angular-starter ``` ``` pnpm create juno -- --template angular-starter ``` ### Path B: Integrate Juno into an existing Angular app Navigate to your existing app: ``` cd your-existing-app ``` and install Juno SDK: * npm * yarn * pnpm ``` npm i @junobuild/core ``` ``` yarn add @junobuild/core @icp-sdk/core @icp-sdk/auth @dfinity/utils ``` ``` pnpm add @junobuild/core @icp-sdk/core @icp-sdk/auth @dfinity/utils ``` ### 2\. Start the Emulator If the Juno admin CLI (required to run the emulator) is not installed yet, run: ``` npm i -g @junobuild/cli ``` Once installed, start the local emulator: ``` juno emulator start ``` Open the Console UI at [http://localhost:5866/](http://localhost:5866/). **Note:** When developing locally, you get an all-in-one emulator that closely mimics the production environment. This includes providing Juno and its Console UI locally. Sign in, create a Satellite, navigate to the **Datastore** section, and create a collection named **demo**. ### 3\. Configure To initialize your project with the Satellite ID you created, configure it in the `juno.config.mjs` file (or other extension), which should be available at the root. Replace `` with the ID. ``` import { defineConfig } from "@junobuild/config";/** @type {import('@junobuild/config').JunoConfig} */export default defineConfig({ satellite: { ids: { development: "", production: "" }, source: "out", predeploy: ["npm run build"] }}); ``` In addition, add also the ID to your `environment.ts` file: ``` export const environment = { satelliteId: ""}; ``` ### 4\. Insert data from your app In `app.component.ts`, initialize the Satellite. Add an `insert` function to persist a document. app.component.ts ``` import { Component } from "@angular/core";import { type Doc, initSatellite, setDoc } from "@junobuild/core";import { environment } from "../environments/environment";@Component({ selector: "app-root", template: ` Key: {{ doc.key }} `, styleUrls: ["./app.component.css"]})export class AppComponent { doc: Doc<{ hello: string }> | undefined = undefined; async ngOnInit() { await initSatellite({ satelliteId: environment.satelliteId }); } async insert() { this.doc = await setDoc({ collection: "demo", doc: { key: window.crypto.randomUUID(), data: { hello: "world" } } }); }} ``` ### 5\. Start the app Start the app, go to [http://localhost:4200](http://localhost:4200) in a browser, click "Insert a document," and you should see the data successfully persisted in your satellite. **What's Next: Going Live:** Once you're ready to deploy your app for others to access, continue to the [Deployment guide](/docs/guides/angular/deploy.md). --- ## Quickstart This example demonstrates how to quickly deploy a basic note-taking app that integrates Juno's core features: * [Authentication](/docs/build/authentication.md): easy-to-use SDKs that support truly anonymous authentication. * [Datastore](/docs/build/datastore.md): a simple key-pair database for storing user data and other information. * [Storage](/docs/build/storage.md): a file storage system to store and serve user-generated content, such as photos. Using the Juno CLI, you can easily scaffold this app. * npm * yarn * pnpm ``` npm create juno@latest -- --template angular-example ``` ``` yarn create juno -- --template angular-example ``` ``` pnpm create juno -- --template angular-example ``` Follow the CLI prompts to choose the note-taking app example and select local development. The CLI will manage all configurations and dependencies, allowing you to focus on exploring and customizing your app right away. --- # Source: https://juno.build/docs/examples/functions/typescript/canister-calls.md # Source: https://juno.build/docs/examples/functions/rust/canister-calls.md # Making Canister Calls in Rust Serverless Functions This example demonstrates how to use **Rust serverless functions** to perform canister calls (such as `transfer_from` on the ICP ledger) in response to Datastore events in your Juno **Satellite**. When a document is added to the `request` collection, a serverless function is triggered to: * Check if the user has enough ICP in their wallet * Transfer ICP from the user's wallet to the Satellite using the ICRC ledger's `transfer_from` method * Mark the request as `processed` if the transfer succeeds This pattern is useful for building workflows that require asset transfers or other canister calls in response to user actions. You can browse the source code here: [github.com/junobuild/examples/tree/main/functions/rust/calls](https://github.com/junobuild/examples/tree/main/functions/rust/calls) --- ## Folder Structure ``` rust/calls/├── src/│ ├── satellite/ # Rust Satellite serverless function│ │ ├── src/│ │ │ ├── lib.rs # Main Rust logic for Satellite│ │ │ ├── services.rs # Helper logic for balance, transfer, status│ │ │ ├── types.rs # Data model for requests│ │ │ ├── ledger_icrc.rs # Ledger helper functions│ │ │ └── ...│ │ ├── satellite.did # Candid interface definition│ │ └── Cargo.toml # Rust package config│ ├── declarations/ # TypeScript declarations for Satellite│ ├── components/ # React frontend components│ ├── services/ # Frontend service logic│ ├── types/ # Frontend type definitions│ ├── main.tsx # Frontend entry│ └── ...├── juno.config.ts # Juno Satellite configuration├── package.json # Frontend dependencies└── ``` --- ## Key Features * **Serverless Canister Calls**: Demonstrates how to perform ICRC ledger calls (e.g., `transfer_from`) from Rust serverless functions. * **Atomic Request Processing**: Ensures that request status is only updated if the transfer succeeds. * **Wallet Balance Checks**: Fails early if the user does not have enough ICP. * **Minimal React UI**: A simple React frontend is included to test and demonstrate the logic. --- ## Main Backend Components * **src/satellite/src/lib.rs**: The entry point for the Satellite serverless function. Triggers the canister call and updates request status on document set. * **src/satellite/src/services.rs**: Helper logic for checking wallet balance, performing the transfer, and updating request status. * **src/satellite/src/types.rs**: Data model for requests and status. * **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function. --- ## Example: Canister Call on Document Set Here’s the actual Rust logic from `lib.rs` and `services.rs`: ``` // src/satellite/src/lib.rsmod env;mod ledger_icrc;mod services;mod types;mod utils;use crate::services::{assert_wallet_balance, set_request_processed, transfer_icp_from_wallet};use crate::types::RequestData;use crate::utils::icp_ledger_id;use ic_cdk::id;use icrc_ledger_types::icrc1::account::Account;use junobuild_macros::on_set_doc;use junobuild_satellite::{include_satellite, OnSetDocContext};use junobuild_utils::decode_doc_data;// Triggered when a new document is set in the "request" collection#[on_set_doc(collections = ["request"])]async fn on_set_doc(context: OnSetDocContext) -> Result<(), String> { // Init data let data: RequestData = decode_doc_data(&context.data.data.after.data)?; let request_amount = data.amount.value; let fee = data.fee.as_ref().map(|fee| fee.value); let ledger_id = icp_ledger_id()?; let from_account: Account = Account::from(context.caller); // Check current account balance assert_wallet_balance(&ledger_id, &from_account, &request_amount, &fee).await?; // Update request status to processed (atomic with transfer) set_request_processed(context.data.key, &data, &context.data.data.after.version)?; // Transfer from wallet to satellite let to_account: Account = Account::from(id()); transfer_icp_from_wallet( &ledger_id, &from_account, &to_account, &request_amount, &fee, ) .await?; Ok(())}include_satellite!(); ``` ``` // src/satellite/src/services.rs/// Asserts that the given account has enough balance to cover the amount and fee.pub async fn assert_wallet_balance( ledger_id: &Principal, from_account: &Account, amount: &u64, fee: &Option,) -> Result<(), String> { let balance = icrc_balance_of(&ledger_id, &from_account).await?; let total = amount.saturating_add(fee.unwrap_or(10_000u64)); if balance < total { return Err(format!("Balance {} is smaller than {}", balance, total)); } Ok(())}/// Transfers ICP from one account to another using `icrc2_transfer_from`.pub async fn transfer_icp_from_wallet( ledger_id: &Principal, from_account: &Account, to_account: &Account, amount: &u64, fee: &Option,) -> Result<(), String> { let result = icrc_transfer_from( &ledger_id, &from_account, &to_account, &Nat::from(amount.clone()), &fee.map(|fee| Nat::from(fee)), ) .await .map_err(|e| format!("Failed to call ICRC ledger icrc_transfer_from: {:?}", e)) .and_then(|result| { result.map_err(|e| format!("Failed to execute the transfer from: {:?}", e)) })?; print(format!("Result of the transfer from is {:?}", result)); Ok(())}/// Updates the request document status to `Processed`.pub fn set_request_processed( key: String, original_data: &RequestData, original_version: &Option,) -> Result<(), String> { let update_data: RequestData = RequestData { status: RequestStatus::Processed, ..original_data.clone() }; let data = encode_doc_data(&update_data)?; let doc: SetDoc = SetDoc { data, description: None, version: original_version.clone(), }; let _ = set_doc_store(id(), "request".to_string(), key, doc)?; Ok(())} ``` **Explanation:** * When a request is submitted, the `on_set_doc` hook is triggered for the `request` collection. * The function checks the user's wallet balance, updates the request status, and performs the ICP transfer atomically. * If any step fails, the entire operation is reverted. * The frontend can monitor request status and balances via the exposed APIs. --- ## How to Run 1. **Clone the repo**: ``` git clone https://github.com/junobuild/examplescd rust/calls ``` 2. **Install dependencies**: ``` npm install ``` 3. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 4. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 5. **Create required collections**: * `request` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) 6. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` 7. **Build the serverless functions** (in a separate terminal): ``` juno functions build ``` The emulator will automatically upgrade your Satellite and live reload the changes. --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.ts` with the production Satellite ID. * Build and deploy the frontend: ``` npm run buildjuno hosting deploy ``` * Build and upgrade the serverless functions: ``` juno functions buildjuno functions upgrade ``` --- ## Notes * This example focuses on the Rust serverless function and canister call integration. The frontend is intentionally minimal and included only for demonstration. * Use this project as a starting point for workflows that require on-chain asset transfers or canister calls in response to user actions. ## Real-World Example Want to see how assertions and serverless logic are used in a live project? Check out [proposals.network](https://proposals.network), an open-source app built with Juno: * GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network) * Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs) This app uses: * `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets * Shared helper modules like `assert`, `delete`, and `types` to keep logic organized * A real-world pattern of chaining asset/document deletions with assertions It’s a great reference for more advanced setups and multi-collection coordination. --- ## References * [Serverless Functions Guide](/docs/guides/rust.md) * [Functions Development](/docs/build/functions.md) * [Rust SDK Reference](/docs/reference/functions/rust/sdk.md) * [Rust Utils Reference](/docs/reference/functions/rust/utils.md) * [Run Local Development](/docs/guides/local-development.md) * [CLI Reference](/docs/reference/cli.md) * [Configuration Reference](/docs/reference/configuration.md) * [Datastore Collections](/docs/build/datastore/collections.md) --- ## Crate Docs These crates are used to build and extend serverless functions in Rust with Juno: * [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration. * [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions. * [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling. * [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console. * [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno. * [icrc-ledger-types](https://docs.rs/icrc-ledger-types): Types for interacting with the ICRC ledger standard. * [ic-cdk](https://docs.rs/ic-cdk): Internet Computer canister development kit for Rust. --- # Source: https://juno.build/docs/reference/functions/typescript/canisters.md # Canisters The following functions can be used to interact with well-known Internet Computer canisters from your serverless functions. **📦 Library:** The Canisters API is provided by the [@junobuild/functions](https://www.npmjs.com/package/@junobuild/functions) library. To add it to your project: * npm * yarn * pnpm ``` npm i @junobuild/functions ``` ``` yarn add @junobuild/functions ``` ``` pnpm add @junobuild/functions ``` You have to follow the pace of the Juno release to ensure compatibility. Refer to the [maintenance guide](/docs/build/functions/development/typescript.md#maintenance) for instructions. --- ## Overview The `@junobuild/functions/canisters` module provides a unified interface for interacting with core Internet Computer canisters from within your Juno serverless functions. It offers: * ⚙️ Type-safe interfaces for well-known IC canisters * 🧩 Modular structure with independent sub-packages * 🔄 Up-to-date Candid declarations and types * 🧪 Battle-tested through production applications --- ## Available Canisters ### Import Structure Each canister is available as a sub-entry. Import the desired module directly from its entry point: | Canister(s) | Import | Status | | --- | --- | --- | | ICP Ledger | `@junobuild/functions/canisters/ledger/icp` | ✅ Canister + Declarations | | ICRC Ledger | `@junobuild/functions/canisters/ledger/icrc` | ✅ Canister + Declarations | | CMC | `@junobuild/functions/canisters/cmc` | ✅ Canister + Declarations | | ckBTC | `@junobuild/functions/canisters/ckbtc` | 📦 Declarations Only | | ckETH | `@junobuild/functions/canisters/cketh` | 📦 Declarations Only | | IC Management | `@junobuild/functions/canisters/ic-management` | 📦 Declarations Only | | NNS | `@junobuild/functions/canisters/nns` | 📦 Declarations Only | | SNS | `@junobuild/functions/canisters/sns` | 📦 Declarations Only | --- ## ICP Ledger You can interact with the ICP Ledger through the class `IcpLedgerCanister`. ### transfer Sends ICP using the Ledger canister `transfer` method. ``` transfer(params: { args: IcpLedgerDid.TransferArgs}): Promise ``` #### Parameters: * `args`: The ledger transfer arguments * `to`: Destination account identifier (AccountIdentifier) * `amount`: Transfer amount object with `e8s` (bigint) * `fee`: Fee object with `e8s` (bigint) * `memo`: Optional transfer memo (bigint) * `from_subaccount`: Optional subaccount (Uint8Array | number\[\]) * `created_at_time`: Optional timestamp object with `timestamp_nanos` (bigint) #### Returns: * `Promise`: The result of the ICP transfer * On success: `{ Ok: bigint }` (block height) * On error: `{ Err: TransferError }` #### Example: ``` import { IcpLedgerCanister } from "@junobuild/functions/canisters/ledger/icp";export const onExecute = async () => { const ledger = new IcpLedgerCanister(); const result = await ledger.transfer({ args: { to: "destination-account-identifier", amount: { e8s: 100_000_000n }, // 1 ICP fee: { e8s: 10_000n }, memo: 0n } }); if ("Ok" in result) { console.log("Transfer successful, block height:", result.Ok); } else { console.error("Transfer failed:", result.Err); }}; ``` --- ## ICRC Ledger Interact with ICRC compatible ledgers through the class `IcrcLedgerCanister`. ### icrc1BalanceOf Returns the balance of an ICRC account. ``` icrc1BalanceOf(params: { account: IcrcLedgerDid.Account}): Promise ``` #### Parameters: * `account`: The account to query * `owner`: Principal of the account owner * `subaccount`: Optional subaccount (Uint8Array | number\[\]) #### Returns: * `Promise`: The token balance (bigint) #### Example: ``` import { IcrcLedgerCanister } from "@junobuild/functions/canisters/ledger/icrc";import { Principal } from "@dfinity/principal";export const onExecute = async () => { const ledger = new IcrcLedgerCanister({ canisterId: "your-icrc-ledger-canister-id" }); const balance = await ledger.icrc1BalanceOf({ account: { owner: Principal.fromText("user-principal"), subaccount: [] } }); console.log("Balance:", balance);}; ``` ### icrc1Transfer Transfers tokens using the ICRC-1 `icrc1_transfer` method. ``` icrc1Transfer(params: { args: IcrcLedgerDid.TransferArg}): Promise ``` #### Parameters: * `args`: Transfer arguments * `to`: Destination account (Account object) * `amount`: Transfer amount (bigint) * `fee`: Optional fee (bigint) * `memo`: Optional memo (Uint8Array | number\[\]) * `from_subaccount`: Optional subaccount (Uint8Array | number\[\]) * `created_at_time`: Optional timestamp (bigint) #### Returns: * `Promise`: The result of the transfer * On success: `{ Ok: bigint }` (block index) * On error: `{ Err: TransferError }` #### Example: ``` import { IcrcLedgerCanister } from "@junobuild/functions/canisters/ledger/icrc";import { Principal } from "@dfinity/principal";export const onExecute = async () => { const ledger = new IcrcLedgerCanister({ canisterId: "your-icrc-ledger-canister-id" }); const result = await ledger.icrc1Transfer({ args: { to: { owner: Principal.fromText("recipient-principal"), subaccount: [] }, amount: 1_000_000n, fee: 10_000n } }); if ("Ok" in result) { console.log("Transfer successful, block index:", result.Ok); } else { console.error("Transfer failed:", result.Err); }}; ``` ### icrc2TransferFrom Transfers tokens using the ICRC-2 `icrc2_transfer_from` method. Allows transferring tokens from another user's account when an approval has previously been granted via `icrc2_approve`. ``` icrc2TransferFrom(params: { args: IcrcLedgerDid.TransferFromArgs}): Promise ``` #### Parameters: * `args`: Transfer-from arguments * `from`: Source account (Account object) * `to`: Destination account (Account object) * `amount`: Transfer amount (bigint) * `fee`: Optional fee (bigint) * `memo`: Optional memo (Uint8Array | number\[\]) * `spender_subaccount`: Optional spender subaccount (Uint8Array | number\[\]) * `created_at_time`: Optional timestamp (bigint) #### Returns: * `Promise`: The result of the transfer-from operation * On success: `{ Ok: bigint }` (block index) * On error: `{ Err: TransferFromError }` #### Example: ``` import { IcrcLedgerCanister } from "@junobuild/functions/canisters/ledger/icrc";import { Principal } from "@dfinity/principal";export const onExecute = async () => { const ledger = new IcrcLedgerCanister({ canisterId: "your-icrc-ledger-canister-id" }); const result = await ledger.icrc2TransferFrom({ args: { from: { owner: Principal.fromText("source-principal"), subaccount: [] }, to: { owner: Principal.fromText("destination-principal"), subaccount: [] }, amount: 500_000n } }); if ("Ok" in result) { console.log("Transfer from successful, block index:", result.Ok); } else { console.error("Transfer from failed:", result.Err); }}; ``` --- ## Cycle Minting Canister (CMC) Interact with the Cycle Minting Canister to convert ICP into cycles using the class `CMCCanister`. ### notifyTopUp Notifies the Cycle Minting Canister that a top-up transfer has been completed. After sending ICP to the CMC top-up account for a canister, the transfer is recorded on the ledger. The CMC does not automatically convert that ICP into cycles — you must call this function to let the CMC know which transaction to process. The CMC will then convert the ICP from the given ledger block into cycles and add them to the specified canister. ``` notifyTopUp(params: { args: CmcDid.NotifyTopUpArg}): Promise ``` #### Parameters: * `args`: Arguments containing: * `block_index`: The ledger block index of the ICP transfer (bigint) * `canister_id`: The canister ID that should receive the cycles (Principal) #### Returns: * `Promise`: The result of the CMC conversion and deposit * On success: `{ Ok: bigint }` (cycles deposited) * On error: `{ Err: NotifyError }` #### Example: ``` import { CMCCanister } from "@junobuild/functions/canisters/cmc";import { IcpLedgerCanister } from "@junobuild/functions/canisters/ledger/icp";import { Principal } from "@dfinity/principal";export const onExecute = async () => { // Step 1: Send ICP to the CMC top-up account const ledger = new IcpLedgerCanister(); const transferResult = await ledger.transfer({ args: { to: "cmc-top-up-account-identifier", amount: { e8s: 100_000_000n }, // 1 ICP fee: { e8s: 10_000n }, memo: 0n } }); if ("Err" in transferResult) { console.error("Transfer failed:", transferResult.Err); return; } const blockIndex = transferResult.Ok; // Step 2: Notify the CMC to convert the ICP to cycles const cmc = new CMCCanister(); const notifyResult = await cmc.notifyTopUp({ args: { block_index: blockIndex, canister_id: Principal.fromText("your-canister-id") } }); if ("Ok" in notifyResult) { console.log("Cycles deposited:", notifyResult.Ok); } else { console.error("Notify failed:", notifyResult.Err); }}; ``` --- ## Declarations-Only Exports The following canisters currently provide Candid type definitions and IDL declarations only. You can use these with the [call](/docs/reference/functions/typescript/ic-cdk.md#call) function for custom interactions. ### ckBTC ``` import { CkBTCBitcoinIdl, CkBTCMinterIdl, type CkBTCBitcoinDid, type CkBTCMinterDid} from "@junobuild/functions/canisters/ckbtc"; ``` ### ckETH ``` import { CkETHMinterIdl, CkETHOrchestratorIdl, type CkETHMinterDid, type CkETHOrchestratorDid} from "@junobuild/functions/canisters/cketh"; ``` ### IC Management ``` import { IcManagementIdl, type IcManagementDid} from "@junobuild/functions/canisters/ic-management"; ``` ### NNS ``` import { NnsGovernanceIdl, NnsSnsWasmIdl, type NnsGovernanceDid, type NnsSnsWasmDid} from "@junobuild/functions/canisters/nns"; ``` ### SNS ``` import { NnsSnsWasmIdl, SnsGovernanceIdl, SnsRootIdl, SnsSwapIdl, type SnsGovernanceDid, type SnsRootDid, type SnsSwapDid} from "@junobuild/functions/canisters/sns"; ``` ### Usage with call() You can use these type definitions with the [call](/docs/reference/functions/typescript/ic-cdk.md#call) function to interact with any canister: ``` import { call } from "@junobuild/functions/ic-cdk";import { IcManagementIdl, type IcManagementDid} from "@junobuild/functions/canisters/ic-management";export const onExecute = async () => { const status = await call({ canisterId: "aaaaa-aa", // Management canister method: "canister_status", args: [ [IcManagementIdl.CanisterIdRecord, { canister_id: "your-canister-id" }] ], result: IcManagementIdl.CanisterStatusResult }); console.log("Canister status:", status);}; ``` --- ## Notes * All canister classes use the [call](/docs/reference/functions/typescript/ic-cdk.md#call) function internally to communicate with the Internet Computer. * The caller's identity is automatically determined by the serverless function execution context. * For admin operations, you can use the [id](/docs/reference/functions/typescript/ic-cdk.md#id) function to get the Satellite's principal, which has admin privileges. * Error handling follows the Result pattern: check for `Ok` or `Err` properties in the response. --- # Source: https://juno.build/docs/reference/cli.md # CLI The Juno CLI provides a variety of tools for managing and deploying projects. ## Installing the Juno CLI To download and install Juno CLI, run the following command: ``` npm i -g @junobuild/cli ``` --- ## Commands The following is a complete list of commands available in the Juno CLI. **Tip:** The CLI automatically runs in non-interactive mode if either a `JUNO_TOKEN` is set or the `--headless` argument is used. The former is set when you set up a [GitHub Actions](/docs/guides/github-actions.md). --- ### Login **Important:** Authenticating your terminal saves sensitive information on your device. We recommend setting up a password to encrypt this file when prompted. Generate an authentication for use in non-interactive environments. ``` Usage: juno login [options]Options: -b, --browser A particular browser to open. supported: chrome|firefox|edge. -e, --emulator Skips the Console UI and logs in your terminal with the emulator (⚠️ local development only). -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. -h, --help Output usage information. ``` The authentication process requires a browser. #### Reusing Access Key If you've previously authenticated your terminal and decide to log in again, the CLI will prompt you about reusing your existing access key. This allows you to reuse your authorization, especially when creating new modules like Satellites or Orbiters. --- ### Logout **Caution:** This action currently does not remove the controllers from Satellites and/or Mission Control and/or Orbiter. It only logs out your local machine by removing the locally saved key (principal). Log out of the current device. ⚠️ This action does not remove the access keys from the module. ``` Usage: juno logout [options]Options: -h, --help Output usage information. ``` --- ### Hosting Deploy or clear the frontend code of your app on your satellite. ``` Usage: juno hosting [options]Subcommands: clear Remove frontend files (JS, HTML, CSS, etc.) from your satellite. deploy Deploy your app to your satellite. ``` --- #### Clear Remove frontend files (JS, HTML, CSS, etc.) from your satellite. ``` Usage: juno hosting clear [options]Options: -f, --fullPath Clear a particular file of your app. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information. ``` **Note:** This command removes existing files from the Satellite and only affects the app assets, your frontend. Your user's uploaded files will not be cleared from your custom collections in the storage. --- #### Deploy Deploy your app to your satellite. ``` Usage: juno hosting deploy [options]Options: --batch Number of files to upload in parallel per batch (default: 50). --clear Clear existing app files before proceeding with deployment. --config Apply configuration after deployment succeeds. --no-apply Submit the deployment as a change but do not apply it yet. -k, --keep-staged Keep staged assets in memory after applying the change. -i, --immediate Deploy files instantly (bypasses the change workflow). -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- The option --keep-staged only applies when --no-apply is NOT used (i.e. the change is applied immediately). ``` --- ### Config Manage your project configuration ``` Usage: juno config [options]Subcommands: apply Apply configuration to satellite. init Set up your project by creating a config file. ``` --- #### Apply Apply configuration to satellite. ``` Usage: juno config apply [options]Options: --force Overwrite configuration without checks. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information. ``` --- #### Init Set up your project by creating a config file. ``` Usage: juno config init [options]Options: --minimal Skip few prompts and generate a config file with a placeholder satellite ID. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information. ``` The `juno config init` command creates a `juno.config` file in the root directory of your project. Depending on your project, it will either create a TypeScript, JavaScript, or JSON file. **Tip:** We recommend using the first two options because they can leverage your IDE's IntelliSense with type hints. This file is necessary for deploying, configuring, or running any other CLI commands for your app. Read more about the [configuration](/docs/reference/configuration.md). --- ### Snapshot Handle snapshot-related tasks. ``` Usage: juno snapshot [options]Subcommands: create Create a snapshot of your current state. delete Delete an existing snapshot. download Download a snapshot to offline files. list List the existing snapshot. upload Upload a snapshot from offline files. restore Restore a previously created snapshot.Options: -t, --target Which module type should be snapshotted? Valid targets are satellite, mission-control or orbiter. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- Targets can be shortened to s for satellite, m for mission-control and o for orbiter. ``` --- #### Upload Upload a snapshot from offline files. ``` Usage: juno snapshot upload [options]Options: --dir Path to the snapshot directory that contains the metadata.json and chunks. -t, --target Which module type should be snapshotted? Valid targets are satellite, mission-control or orbiter. --target-id The module ID of a specific target to upload the snapshot to. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- Targets can be shortened to s for satellite, m for mission-control and o for orbiter. ``` --- ### Stop Stop a module. ``` Usage: juno stop [options]Options: -t, --target Which module type should be stopped? Valid targets are satellite, mission-control or orbiter. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- Targets can be shortened to s for satellite, m for mission-control and o for orbiter. ``` --- ### Start Start a module. ``` Usage: juno start [options]Options: -t, --target Which module type should be started? Valid targets are satellite, mission-control or orbiter. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- Targets can be shortened to s for satellite, m for mission-control and o for orbiter. ``` --- ### Upgrade Upgrade a module to a new version. ``` Usage: juno upgrade [options]Options: -t, --target Which module type should be upgraded? Valid targets are satellite, mission-control or orbiter. -s, --src A path to a specific local gzipped WASM file to publish. --clear-chunks Clear any previously uploaded WASM chunks (applies if the WASM size is greater than 2MB). --no-snapshot Skip creating a snapshot before upgrading. -r, --reset Reset to the initial state. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- Resetting a mission control is not possible.- Targets can be shortened to s for satellite, m for mission-control and o for orbiter. ``` **Important:** * We recommend that you stay current with the Juno releases, as some features may not perform correctly in the [console](/docs/terminology.md#console) if your modules are outdated. * Upgrading requires a stable internet connection for a successful process. The CLI automatically runs in non-interactive mode if either a JUNO\_TOKEN is set or the --headless argument is used. --- ### Changes Review and apply changes submitted to your module. ``` Usage: juno changes [options]Subcommands: apply Apply a submitted change. list List all submitted or applied changes. reject Reject a change. ``` --- #### Apply Apply a submitted change. ``` Usage: juno changes apply [options]Options: -i, --id The ID of the change to apply. --snapshot Create a snapshot before applying. --hash The expected hash of all included changes (for verification). -k, --keep-staged Keep staged assets in memory after applying the change. -h, --help Output usage information. ``` --- #### List List all submitted or applied changes. ``` Usage: juno changes list [options]Options: -a, --all Search through all changes, not just the 100 most recent. -e, --every Include changes of any status (default is only submitted ones). -h, --help Output usage information. ``` --- #### Reject Reject a change. ``` Usage: juno changes reject [options]Options: -i, --id The ID of the change to reject. --hash The expected hash of all included changes (for verification). -k, --keep-staged Keep staged assets in memory after applying the change. -h, --help Output usage information. ``` --- ### Emulator Handle tasks related to the emulator like starting/stopping a local network. ``` Usage: juno emulator [options]Subcommands: start Start the emulator for local development. stop Stop the local network. wait Wait until the emulator is ready. ``` --- #### Start Start the emulator for local development. ``` Usage: juno emulator start [options]Options: -l, --lang Specify the language for building the serverless functions: rust, typescript or javascript. --cargo-path Path to the Rust manifest. --source-path Optional path to the TypeScript or JavaScript entry file. -w, --watch Rebuild your functions automatically when source files change. -h, --help Output usage information.Notes:- The language and path options are only used in combination with watch.- If no language is provided, the CLI attempts to determine the appropriate build.- Language can be shortened to rs for Rust, ts for TypeScript and mjs for JavaScript.- Use --cargo-path to specify a specific crate path. For Rust builds, this maps to --manifest-path for cargo build. For TypeScript and JavaScript, it points to the Rust crate (commonly "Sputnik") that imports the functions.- An optional --source-path to specify the source file for TypeScript and JavaScript (e.g. index.ts or index.mjs).- The watch option rebuilds when source files change, with a default debounce delay of 10 seconds; optionally, pass a delay in milliseconds. ``` --- #### Wait Wait until the emulator is ready. ``` Usage: juno dev wait [options]Options: -t, --timeout Timeout for the emulator to be ready (in ms, default 2min). -h, --help Output usage information. ``` --- ### Functions Build and upgrade your satellite's serverless functions. ``` Usage: juno functions [options]Subcommands: build Build your functions. eject Scaffold the necessary files for developing your serverless functions. init Alias for eject. publish Publish a new version of your functions. upgrade Upgrade your satellite's serverless functions.Notes:- The local server supports live reloading.- You can use fn as a shortcut for functions. ``` --- #### Build Build your serverless functions. ``` Usage: juno functions build [options]Options: -l, --lang Specify the language for building the serverless functions: rust, typescript or javascript. --cargo-path Path to the Rust manifest. --source-path Optional path to the TypeScript or JavaScript entry file. -w, --watch Rebuild your functions automatically when source files change. -h, --help Output usage information.Notes:- If no language is provided, the CLI attempts to determine the appropriate build.- Language can be shortened to rs for Rust, ts for TypeScript and mjs for JavaScript.- Use --cargo-path to specify a specific crate path. For Rust builds, this maps to --manifest-path for cargo build. For TypeScript and JavaScript, it points to the Rust crate (commonly "Sputnik") that imports the functions.- An optional --source-path to specify the source file for TypeScript and JavaScript (e.g. index.ts or index.mjs).- The watch option rebuilds when source files change, with a default debounce delay of 10 seconds; optionally, pass a delay in milliseconds. ``` --- #### Eject Generate the required files to begin developing serverless functions in your project. ``` Usage: juno functions eject [options]Options: -l, --lang Specify the language for building the serverless functions: rust, typescript or javascript. -h, --help Output usage information.Notes:- Language can be shortened to rs for Rust, ts for TypeScript and mjs for JavaScript. ``` --- #### Publish Publish a new version of your serverless functions. ``` Usage: juno functions publish [options]Options: --no-apply Submit the release as a change but do not apply it yet. -k, --keep-staged Keep staged assets in memory after applying the change. -s, --src A path to a specific local gzipped WASM file to publish. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- The option --keep-staged only applies when --no-apply is NOT used (i.e. the change is applied immediately). ``` --- #### Upgrade Upgrade your serverless functions. ``` Usage: juno functions upgrade [options]Options: --cdn Select a previously published WASM file from the CDN (interactive). --cdn-path Use a specific published WASM file from the CDN. -s, --src A path to a specific local gzipped WASM file to publish. --clear-chunks Clear any previously uploaded WASM chunks (applies if the WASM size is greater than 2MB). --no-snapshot Skip creating a snapshot before upgrading. -r, --reset Reset to the initial state. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information.Notes:- If no option is provided, the default local build output will be used.- If --src is specified, it takes precedence over any CDN options.- Use --cdn to interactively select from recent published releases. ``` --- ### Run Run a custom script in the CLI context. ``` Usage: juno run [options]Options: -s, --src The path to your JavaScript or TypeScript script. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. -h, --help Output usage information. ``` --- ### Open Open your satellite in your browser. ``` Usage: juno open [options]Options: -b, --browser A particular browser to open. supported: chrome|firefox|edge. -c, --console Open satellite in the console. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information. ``` --- ### Status Check the status of the modules. ``` Usage: juno status [options]Options: -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. -h, --help Output usage information. ``` --- ### Version Check the version of the CLI. ``` Usage: juno version [options]Options: -h, --help Output usage information. ``` --- ### Who am I? Display your current profile, access key, and links to your satellite. ``` Usage: juno whoami [options]Options: -h, --help Output usage information. -m, --mode Choose which environment to use (production, staging, development). Defaults to production if omitted. -p, --profile Specify an optional profile to use (e.g. personal, team). Useful when managing multiple Mission Controls. --container-url Override a custom container URL. If not provided, defaults to production or the local container in development mode. --console-url Specify a custom URL to access the developer Console. ``` --- ## Environment Some CLI flags affect the context of your commands, such as which environment you're working in or which identity you're using. These flags are global and apply to most commands. --- ### Mode The `--mode` flag lets you target a specific environment when executing CLI commands. This is useful for working across development, staging, and production setups. ``` juno login --mode developmentjuno hosting deploy --mode staging ``` The value for `--mode` can be any string. If omitted, it defaults to production. **Important:** The `development` value is reserved. When you use `--mode development`, the tooling automatically understands that you are working with the local emulator. --- ### Profile The optional `--profile` flag lets you switch between different identities. Useful when working with multiple Mission Controls. ``` juno login --profile teamjuno hosting deploy --profile team --mode staging ``` It accepts any string. If omitted, no profile is used. --- ### Local Persistence Unless you run it in headless mode with a token, the Juno CLI stores data locally in the following OS-specific user's variables path to work properly. | OS | Path | | --- | --- | | Mac | `~/Library/Preferences/juno-nodejs` | | Windows | `%APPDATA%\juno-nodejs\Config` (for example, `C:\Users\USERNAME\AppData\Roaming\juno-nodejs\Config`) | | Linux | `~/.config/juno-nodejs` (or `$XDG_CONFIG_HOME/juno-nodejs`) | These config files are created based on the selected `--profile` and `--mode`: | File | Encrypted | Purpose | | --- | --- | --- | | `juno[-profile][-mode]` | ✅ | Stores the [access key](/docs/miscellaneous/access-keys.md) ([principal](/docs/terminology.md#principal)) and list of modules. | | `juno[-profile][-mode]-cli-settings` | | Stores CLI preferences, e.g. whether the access key file is encrypted (to avoid unnecessary prompts). | | `juno[-profile][-mode]-cli-state` | | Stores ephemeral state like applied config hashes. | --- # Source: https://juno.build/docs/build/storage/collections.md # Source: https://juno.build/docs/build/datastore/collections.md # Collections You can create or update a collection in the "Collections" tab in Juno's console under the [datastore](https://console.juno.build/datastore) view. --- ## Configuration Each collection has a set of configurable options that define its behavior and limitations: | Option | Mandatory | Description | | --- | --- | --- | | Key | Yes | A unique identifier for the collection. The key that you will use in your code to interact with a particular collection. | | Read permission | Yes | Defines who can read documents in the collection. See ([Permissions](#permissions)) below. | | Write permission | Yes | Defines who can create, update, or delete documents. See ([Permissions](#permissions)) below. | | Memory | Yes | Specifies whether the collection uses `heap` or `stable` memory. This setting is permanent and cannot be changed after creation. The default is `stable` memory. For more information, see the related [documentation](/docs/miscellaneous/memory.md). | | Max changes per user | No | Limits the number of documents a single user can create, update, or delete in the collection. This helps maintain fair resource distribution across users. | | Max capacity | No | The maximum number of documents that can be stored in the collection, applying to the entire collection regardless of individual users. | | Max updates per minute | No | Limits the number of creation, update and delete operations per minute to prevent excessive updates. | | Immutable permissions | No | If enabled, read and write permissions cannot be modified after creation. | --- ## Permissions Permissions define who can read and write documents in a collection. Writing includes creating, updating, and deleting documents. | Permission | Description | | --- | --- | | **Public** | Anyone can read or write documents in the collection. | | **Private** | Only the creator (owner) of a document can read or write to it. However, note that since Satellite administrators manage the underlying infrastructure, they have the technical ability to modify access rules by changing its source code. | | **Managed** | The owner of a document, the administrator and editor of the Satellite can read or write to it in the collection. | | **Restricted** | Only Satellite administrator and editor can read or write any document in the collection. | If not set to immutable, you can modify the permissions at any time, and the changes will take effect immediately. **Tip:** Any collection with read permissions set to `public`, `managed` or `restricted` will allow the developer to view its content in the console under the [datastore](https://console.juno.build/datastore) view. --- # Source: https://juno.build/docs/reference/configuration.md # Source: https://juno.build/docs/build/hosting/configuration.md # Configuration You can customize your hosting environment to fit your needs, including: * Specify which `source` files in your local project directory you want to deploy? ([Learn how.](#source)) * Ignore some files during deployment. ([Learn how.](#ignore-files)) * Configure HTTP `headers` to pass along additional information about a request or a response. ([Learn how.](#http-headers)) * Serve a customized 404 page. ([Learn how.](#customize-a-404not-found-page)) * Set up `redirects` for pages that you've moved or deleted. ([Learn how.](#redirects)) * Set up `rewrites`. ([Learn how.](#rewrites)) * Customize file `compression` for optimal performance. ([Learn how.](#precompress)) * Customize the `encoding` behavior of your files. ([Learn how.](#encoding-types)) * Allow your project to be embedded as an `iframe`. ([Learn how.](#iframe)) * Customize `assertions` to modify the default verification behavior of the CLI. ([Learn how.](#assertions)) --- ## Where do you define your Hosting configuration? Your hosting configuration is defined in the Juno [configuration](/docs/reference/configuration.md) file, which is automatically created when you run [juno config init](/docs/reference/cli.md#init) or [juno hosting deploy](/docs/reference/cli.md#deploy) for the first time. --- ## How do you apply your changes? To apply any changes, execute the [juno config apply](/docs/reference/cli.md#apply) command with the CLI. --- ## Options The list below outlines the available hosting options you can configure to tailor your hosting. ### Source The `source` field specifies the directory that contains the built assets for your Satellite. This is typically the output directory generated by your build process after running a command like `npm run build`. Commonly, or if you are using the templates, these are the folders that can be set as the `source` field: | Framework | Source | | --- | --- | | Next.js | `out` | | React, Astro, or Vue | `dist` | | SvelteKit | `build` | | Angular | `dist//browser` | 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. juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "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: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", ignore: ["**/*.txt", ".tmp/"] }}); ``` ### 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: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "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](https://juno.build/docs/build/storage#upload-file) file to your "Storage" and within the configuration, both headers will be set in the response. ### Customize a 404/Not Found page By default, all unknown paths are automatically rewritten to `/index.html`. However, if you wish to serve a custom `404 Not Found` error when a user attempts to access a non-existent page, you can do so without requiring additional configuration. Simply upload a custom `404.html` file to your Satellite that should be served from the root path of your site. ### 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. juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "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: | Field | Description | | --- | --- | | **source** | This `source` attribute works similarly to Git's `.gitignore`, and you can specify which files match the redirects using globs. | | **location** | A relative path to where the browser should make a new request. | | **code** | The HTTPS response code. Use a type of `301` for 'Moved Permanently' or `302` for 'Found' (Temporary Redirect). | ### 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. juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "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. ### GZIP When deploying your application, the CLI automatically searches for files matching the pattern `**/*.+(css|js|mjs|html)` in the `source` folder to optimize them using Gzip compression. This improves the performance of your app when it is served on the web. By default, precompression stores **both** the original and compressed versions in Storage. You can disable it entirely or customize which files are precompressed, whether to keep originals, and which compression algorithm to use. **Note:** If you change the precompress configuration and your project has already been deployed, run `juno hosting clear` before redeploying to ensure you change is applied. #### Disable precompression Set the `precompress` option to `false` in your configuration: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", precompress: false }}); ``` #### Customize the file matching pattern If you want to customize the default pattern `**/*.+(css|js|mjs|html)` to better suit your needs, you can specify your own pattern. For example: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", precompress: { pattern: "**/*.jpg" // precompress JPEG files only } }}); ``` #### Decide what happens to original files The `mode` option controls what happens to the original files after compression: * `"both"` — upload both the original and the compressed version. _(default)_ * `"replace"` — upload only the compressed version and serve it with the appropriate `Content-Encoding` header. **Warning:** If you use `replace` for HTML, some social media crawlers (e.g. Twitter, LinkedIn) may not be able to fetch your pages correctly, resulting in missing or broken social previews. To avoid this, instead of providing a single precompression rule, it's recommended to fine-tune the behavior using an **array of rules** (([see below](#use-multiple-rules))). juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", precompress: { mode: "replace" } }}); ``` #### Choose the compression algorithm By default, precompression uses **Gzip** (`algorithm: "gzip"`) because it offers a good balance between compression speed, compatibility, and size. You can switch to **Brotli** (`algorithm: "brotli"`) for potentially smaller files, especially for text-based assets such as those compressed by default like HTML, CSS, and JavaScript. juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", precompress: { algorithm: "brotli" } }}); ``` #### Use multiple rules **Tip:** This strategy works great for modern static sites. In some cases, particularly when using `mode: replace`, you may want to apply different precompression strategies depending on the file type. For example, using replace for JavaScript and CSS files, but doing so for HTML can break social media previews. To handle this, the precompress option also accepts an array of rules: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", precompress: [ { pattern: "**/*.+(js|mjs|css)", algorithm: "brotli", mode: "replace" }, { pattern: "**/*.html", algorithm: "brotli", mode: "both" } ] }}); ``` ### Encoding types 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: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", encoding: [["**/releases/*.gz", "identity"]] }}); ``` ### 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. juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", storage: { iframe: "same-origin" } }}); ``` ### 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: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "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`: juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist", assertions: { heapMemory: false } }}); ``` --- # Source: https://juno.build/docs/create-a-satellite.md # Create a Satellite When you're ready to deploy your project to production, you'll need to create a [Satellite](/docs/terminology.md#satellite). 1. To get started, sign-in to the Juno [Console](https://console.juno.build). 2. Click **Launch your first Satellite**. 3. Enter a name for your Satellite (note: this is for display purposes only and does not need to be unique). 4. Select whether you're deploying a **Website** or **Application**. 5. Confirm with **Create a Satellite.** 6. The platform will then create your Satellite and provision its resources. 7. Once the process is complete, click **Continue** to access the service page. 🎉 You’re all set! You can now deploy your frontend app, static website, or publish your serverless functions to production. ➡️ Continue with the [deployment](/docs/category/deployment.md) guides to take the next step. --- **Note:** Choose **Website** if you're deploying a static site, blog, portfolio, etc. Choose **Application** if your project needs user sign-in, data management, or serverless functions. You can change this later in your Satellite "Hosting" settings. --- # Source: https://juno.build/docs/guides/github-actions/deploy-frontend.md # Deploy Frontend This section describes how to deploy the frontend of your project using GitHub Actions. The frontend typically includes all client-side assets — such as HTML, CSS, JavaScript, and other static files—that are served to users. With this setup, changes pushed to your repository can be automatically deployed based on your workflow configuration. --- ## Configuration To configure an action to deploy your frontend assets, follow these steps: 1. Create or edit a `deploy.yml` file in the `.github/workflows` subfolder of your repository. If the folders do not exist, create those. 2. Paste the following code into the file: * npm * yarn * pnpm .github/workflows/deploy.yml ``` name: Deploy to Junoon: workflow_dispatch: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Install Dependencies run: npm ci - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/deploy.yml ``` name: Deploy to Junoon: workflow_dispatch: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Enable Corepack run: corepack enable - name: Activate Yarn run: corepack prepare yarn@1.x --activate - name: Install Dependencies run: yarn install --frozen-lockfile - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/deploy.yml ``` name: Deploy to Junoon: workflow_dispatch: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - uses: pnpm/action-setup@v4 with: version: 10 - name: Install Dependencies run: pnpm i --frozen-lockfile - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` Whenever code is pushed to your `main` branch, this action performs the following tasks: it checks out your repository, installs dependencies. It then utilizes the [junobuild/juno-action](https://github.com/junobuild/juno-action) GitHub Action to build and deploy your dapp. That's it—your pipeline is set! 🥳 **Note:** If your `juno.config` file does not build your application using a `predeploy` field, you might need to add an additional step to your YAML file to do so: ``` - name: Build run: npm run build ``` --- ## Modes The GitHub Action is basically just an environment that proxies commands to the CLI. That’s why you can also pass the `--mode` option flag. Useful, for example, if you want to deploy your app for a `staging` instead of the default `production`. You can either hardcode the mode in the arguments: ``` - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy --mode staging env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` Or, if you're using an environment variable, pass it like this: ``` - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy --mode ${{ env.JUNO_MODE }} env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} JUNO_MODE: staging ``` --- ## Optimization & Best Practices Below are key considerations to ensure efficient and cost-effective deployment of your project. ### Build Reproducibility Only new resources will be deployed to your Satellite. Changes are detected through sha256 comparison. Therefore, ensuring the build reproducibility of your application is crucial to accurately identify and deploy the necessary updates. ### Deployment Costs Deploying new assets consumes \[cycles\], and the cost increases with both the frequency of deployments and the number of items to deploy. While the above code snippet demonstrates a more frequent lifecycle, as a general recommendation, consider minimizing your deployment expenses with less frequent deployments. For instance, you can trigger the action on releases instead. ``` on: release: types: [released] ``` --- # Source: https://juno.build/docs/guides/vue/deploy.md # Source: https://juno.build/docs/guides/sveltekit/deploy.md # Source: https://juno.build/docs/guides/react/deploy.md # Source: https://juno.build/docs/guides/nextjs/deploy.md # Source: https://juno.build/docs/guides/docusaurus/deploy.md # Source: https://juno.build/docs/guides/astro/deploy.md # Source: https://juno.build/docs/guides/angular/deploy.md # Deploy an Angular App Use this guide to deploy your project to production. ## 1\. Create a container 1. Log in to the [Juno Console](https://console.juno.build). 2. Click the **Launch a new satellite** button (the container for your project) from the launchpad 3. Enter a **name** and select **Website** 4. Confirm with **Create a Satellite** 5. The platform will then provision its resources. 6. Once the process is complete, click Continue to access the overview page. ## 2\. Configure your project Create a `juno.config.mjs` file at the root of your project. Replace the `PROD_SATELLITE_ID` with the ID of the Satellite you created earlier and `dist//browser` with your project's name. ``` import { defineConfig } from "@junobuild/config";/** @type {import('@junobuild/config').JunoConfig} */export default defineConfig({ satellite: { ids: { development: "", production: "" }, source: "dist//browser", predeploy: ["npm run build"] }}); ``` ## 3\. How to deploy You can deploy using either ([GitHub Actions](#github-actions-deployment)) or ([CLI](#cli-deployment)) (command line interface). ### GitHub Actions deployment 1. From your Satellite's overview, navigate to the **Setup** tab. 2. Click on **Add an access key**. 3. Generate a new key with the default option. Click **Submit**. 4. Upon successful creation, a **Secret token** will be displayed. Copy the value and save it as an [encrypted secret](https://docs.github.com/en/actions/security-guides/encrypted-secrets) in your GitHub repository or organization, using the key `JUNO_TOKEN`. 5. Create a `deploy.yml` file in the `.github/workflows` subfolder of your repo. 6. Add the following workflow configuration: * npm * yarn * pnpm .github/workflows/deploy.yml ``` name: Deploy to Junoon: workflow_dispatch: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Install Dependencies run: npm ci - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/deploy.yml ``` name: Deploy to Junoon: workflow_dispatch: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Enable Corepack run: corepack enable - name: Activate Yarn run: corepack prepare yarn@1.x --activate - name: Install Dependencies run: yarn install --frozen-lockfile - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/deploy.yml ``` name: Deploy to Junoon: workflow_dispatch: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - uses: pnpm/action-setup@v4 with: version: 10 - name: Install Dependencies run: pnpm i --frozen-lockfile - name: Deploy to Juno uses: junobuild/juno-action@main with: args: hosting deploy env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` ### CLI deployment 1. Install the CLI * npm * yarn * pnpm ``` npm i -g @junobuild/cli ``` ``` yarn global add @junobuild/cli ``` ``` pnpm add -g @junobuild/cli ``` 2. Authenticate the CLI. This will open the Juno Console. ``` juno login ``` **Tip:** An access token is used to identify your terminal. That's why the CLI asks whether you want to encrypt it with a password. For security reasons, it's recommended that you do so. 3. In the browser window, click **Authorize** to grant permission. 4. Deploy your site: ``` juno hosting deploy ``` --- # Source: https://juno.build/docs/build/storage/development.md # Source: https://juno.build/docs/build/hosting/development.md # Source: https://juno.build/docs/build/datastore/development.md # Source: https://juno.build/docs/build/analytics/development.md # Development Learn how to track page views, custom events, and performance metrics. --- ## Page views Page views, such as when a visitor opens your website or navigates to a subpage, are automatically tracked once you have configured, initialized, and deployed your application with the analytics module. There's **no need** for additional development work! However, if you (really) want to trigger page view tracking manually, you can do so using the `trackPageView()` function provided by the SDK. ``` import { trackPageView, trackPageViewAsync } from "@junobuild/analytics";trackPageView(); // or await trackPageViewAsync(); ``` --- ## Track custom events Custom events can be tracked using the `trackEvent` function. You need to provide a `name` for the event, and you can include up to 10 custom `metadata` fields. **Note:** This is an option. As explained in the previous chapter, the library will take care of gathering insightful anonymous data as soon as it is configured and initialized. Custom events are useful if you want to take an extra step and collect your own specific information. Here's an example of how to use it: ``` import { trackEvent, trackEventAsync } from "@junobuild/analytics";// Fire-and-forgettrackEvent({ name: "Your custom event", metadata: { your_key: "A value", your_other_key: "Another value" }});// Or await it if neededawait trackEvent({ name: "Your custom event", metadata: { your_key: "A value", your_other_key: "Another value" }}); ``` Use the `async` version if you're tracking events for which you want to absolutely ensure delivery before continuing the flow — for example, before navigating away or submitting critical user input. That said, the tracker sends data using `keepalive` fetch requests by default, so in most cases there’s no difference in reliability — the choice is mostly a matter of convenience and flow control. **Important:** For scalability and optimization reasons, the data collected must adhere to certain rules, particularly regarding their length. For instance, a randomly generated key should not exceed 36 bytes in length. For detailed information about these rules, please refer to Juno's GitHub [repository](https://github.com/junobuild/juno). --- ## Campaign tracking with UTM parameters Juno Analytics automatically supports [UTM parameters](https://en.wikipedia.org/wiki/UTM_parameters) out of the box. These are standard query parameters (like `utm_source`, `utm_medium`, and `utm_campaign`) commonly added to links in newsletters, ads, and social posts to help you understand how visitors reach your app. They're added to the end of a URL as query parameters. For example: ``` ?utm_source=newsletter&utm_medium=email&utm_campaign=rocket-launch ``` As long as your URLs include UTM tags, campaign data will be collected and shown in your dashboard — no additional setup needed. ### Common UTM parameters | Parameter | Required | Description | Example | | --- | --- | --- | --- | | `utm_source` | ✅ | Where the traffic comes from | `newsletter`, `twitter`, `github` | | `utm_medium` | | The channel used | `email`, `social` | | `utm_campaign` | | The name of the campaign | `rocket-launch` | | `utm_term` | | Keywords for paid search | `juno+analytics` | | `utm_content` | | Distinguish between different links | `header-button`, `footer-link` | Only the `utm_source` field is mandatory. If it's missing, the campaign will not be tracked. --- # Source: https://juno.build/docs/guides/docusaurus.md # Docusaurus Explore how to deploy a Juno project developed with Docusaurus. [## 📄️ Deploy Learn how to deploy your Docusaurus project to Juno. Follow the deployment guide to configure static exports, set up your Satellite, and publish your site to production.](/docs/guides/docusaurus/deploy.md) --- # Source: https://juno.build/docs/guides/e2e.md # End-to-End Testing End to end (E2E) testing helps you verify that your application behaves as expected when deployed. It covers real workflows — from serverless functions to client calls — and helps catch issues that unit tests might miss. This page outlines how to approach E2E testing with Juno. It includes recommendations and patterns. --- ## Frameworks We suggest [Playwright](https://playwright.dev/), but [Cypress](https://www.cypress.io/) or other frameworks will work. Choose whatever fits your project best. That being said, integrating authentication is easier in Playwright given that a plugin is available (see next chapter). --- ## Authentication If your application require authentication, we recommend using the Playwright plugin for Internet Identity maintained by the DFINITY foundation: 👉 [github.com/dfinity/internet-identity-playwright](https://github.com/dfinity/internet-identity-playwright) It handles the full login flow programmatically, allowing your tests to sign in without user interaction. ### Example usage After installing the plugin, you can write a test like this: ``` import { testWithII } from "@dfinity/internet-identity-playwright";testWithII("should sign-in with a new user", async ({ page, iiPage }) => { await page.goto("/"); await iiPage.signInWithNewIdentity();}); ``` --- ## Continuous Integration To run end-to-end tests in CI, we recommend using the `junobuild/satellite` image. This image runs a headless Satellite (spun with a predictable ID `jx5yt-yyaaa-aaaal-abzbq-cai`) with all core services enabled. It's a bit faster to start and does not require using the Console UI. --- ### Configuration In your `juno.config.ts`, make sure to set the `development` ID to match the one used by the image, and set the emulator to run the `junobuild/satellite` image. If you're using a different image like Skylab, you can make this configuration dynamic based on the mode received by `defineConfig`. You can also replace `development` with `test` or any other mode. Adapt as you wish. ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { development: "jx5yt-yyaaa-aaaal-abzbq-cai", production: "" }, source: "out", collections: { datastore: [ { collection: "notes", read: "managed", write: "managed", memory: "stable" } ], storage: [ { collection: "images", read: "managed", write: "managed", memory: "stable" } ] } }, emulator: { runner: { type: "docker" }, satellite: {} }}); ``` The configuration above also defines the collections used by the application under test. In the next chapter, we'll apply this config before running the tests. --- ### GitHub Actions To run the tests in your CI, you can either use the [GitHub Actions](/docs/guides/github-actions.md) or install the CLI manually. In the example below, we install the CLI because we chain multiple commands. ``` name: E2E Testson: pull_request: workflow_dispatch:jobs: e2e: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Install dependencies run: npm ci - name: Install Juno CLI run: npm i -g @junobuild/cli - name: Run emulator run: | set -e juno emulator start --headless & juno emulator wait juno login --emulator --mode development --headless juno config apply --mode development --headless - name: Run tests run: npm run e2e:ci - name: Upload Playwright report on failure uses: actions/upload-artifact@v4 if: ${{ failure() }} with: name: playwright-report path: playwright-report/ retention-days: 3 - name: Upload Playwright results on failure uses: actions/upload-artifact@v4 if: ${{ failure() }} with: name: test-results path: test-results/ retention-days: 3 may-merge: needs: ["e2e"] runs-on: ubuntu-latest steps: - name: Cleared for merging run: echo OK ``` So, how it works: * We start by checking out the code, installing Node.js, and running `npm ci` to install your project dependencies. * As mentioned, instead of the Juno GitHub Actions, we install the Juno CLI globally so we can use it in the next steps. * We then run the emulator using `juno emulator start --headless`, which launches the `junobuild/satellite` Docker image (defined in the `juno.config`) in the background, and follow up with: * `juno emulator wait` to ensure the emulator is ready before continuing. * `juno login` sets up authentication against the emulator in headless mode. This way the CLI can operate the Satellite — required for the next step. * `juno config apply` applies the configuration and sets the collections required by the project. * Once everything is ready, we run the end-to-end tests via `npm run e2e:ci`. Replace with the command that runs your tests in headless mode. * If the tests fail, Playwright reports and raw test results are uploaded as artifacts to help debugging. * Finally, if everything passes, the `may-merge` job marks the PR as cleared. That's it. Minimal setup, no need for the Console UI, and everything runs headlessly in CI. --- # Source: https://juno.build/docs/reference/emulator.md # Emulator The emulator provides a complete local environment to build, test, and run your project without deploying anything live. There are two images available, depending on your needs: [## 📄️ Skylab The junobuild/skylab image is an all-in-one emulator for local development. It bundles everything you need to build, test, and explore the Juno ecosystem:](/docs/reference/emulator/skylab.md) [## 📄️ Satellite Unlike Skylab, the image junobuild/satellite runs a single Satellite in a headless environment, without the Console UI. It always mounts the same Satellite, using the fixed ID jx5yt-yyaaa-aaaal-abzbq-cai.](/docs/reference/emulator/satellite.md) [## 📄️ Infrastructure In the local environment, several services (which can be either canisters or apps on the Internet Computer) are automatically spun up. This ensures that developers have everything they need to start building right out of the box. Thanks to built-in plugins and tooling, these services are automatically integrated into the environment, eliminating the need for developers to manually manage their bindings.](/docs/reference/emulator/infrastructure.md) --- # Source: https://juno.build/docs/faq.md # FAQ ### Where do I find support? For help and questions about best practices, join our [Discord](https://discord.gg/wHZ57Z2RAG) channel. You can report issue or bug on [GitHub](https://github.com/junobuild/juno). ### How much does it cost? Getting started is free. Developers are responsible for operating costs. Transaction costs may apply for some features. [Detailed information and estimations](/docs/pricing.md) are available. ### What are credits? Credits are not money or tokens, they're simply Juno's way of helping you get started, like saying "drinks on us". * 1 credit lets you spin up one module without requiring payment (see [Pricing](/docs/pricing.md)). * Every new developer starts with 2 credits, enough to create a Mission Control and a Satellite to get going. Sometimes, additional credits can be granted - for example, during onboarding or when launching exciting projects. Reach out if you need more. ### How do I verify an upgrade? Before approving an upgrade, developers can verify the proposed changes by checking the release details on [GitHub](https://github.com/junobuild/juno/releases). Each release includes a list of modules proposed for update, along with a checksums.txt file that contains the SHA-256 hashes of the module binaries. For example: ``` 68c1978c4fe7ad98cc95fd73e20f42feaf66f010e8fe91a7047116001dfcab13 ./console.wasm.gz31647e69cd5a3639bda65300e37a8f44eb5feb3562e81f29c1ab17a31a867b42 ./mission_control.wasm.gz87a18c56889690a05adf2b4289b911714c0ac6449108ae0c588203680c2c54d2 ./observatory.wasm.gz5a74b1224a5a5d14e5d9f0ebe49a4ba6d51780dbde983525b5ef16a976c28f14 ./orbiter.wasm.gz40b77e22e13aee86ac3872352640443fa27a9bdc098847f15bfafe844a9f58ab ./satellite.wasm.gz ``` If the hash of a module differs from the one listed in the release, the upgrade should not be approved. It's also important to check the release notes to confirm which modules are actually included in the update, as the build process always prints all hashes. Developers can also validate the data by querying the [CDN](https://github.com/junobuild/cdn), which provides each module with a certificate. Since the CDN itself is backed by a Juno Satellite, this guarantees that the delivered WebAssembly modules have not been tampered with. For reproducibility, developers can run the official Docker build for Juno and its modules. If everything matches, the same versions should be produced. ### What happens if Juno disappears? In the unlikely event of Juno's disappearance, you retain full control over your creations. They would continue to function independently without any reliance on Juno. ### Can I just deploy my website on the Internet Computer? Absolutely! With Juno, you have the flexibility to choose the level of functionality you want for your project. Whether you simply want to host your static website on the [Internet Computer](https://internetcomputer.org/) or take advantage of Juno's rich features like [authentication](/docs/build/authentication.md), [datastore](/docs/build/datastore.md), and [storage](/docs/build/storage.md) for building dynamic dapps, the choice is yours. ### Is Juno a project of the DFINITY foundation? No, Juno is an independent project. In 2024, we received a [Developer Grant](https://dfinity.org/grants/) from the [DFINTIY foundation](https://dfinity.org) to grow the ecosystem, ease developer onboarding, and enhance visual communication. For 2025, the Foundation is funding the project to further expand the developer ecosystem and advance the Internet Computer. ### Does Juno exercise control over developers' work? No, Juno does not exert any control over developers' work. Juno is designed to provide developers with true control and autonomy over their projects. Developers have full ownership and control over their modules, and the applications they build on the platform. Juno's philosophy aligns with the principles of Web3, empowering developers with transparency, decentralization, and the freedom to create and innovate without external interference. ### How does Juno differ from Firebase? Besides the fundamental differences between the Web2 and Web3 approaches, which empower developers using Juno with true control and future governance over their work, there are additional distinctions that apply regardless of the underlying philosophy. #### Source Firebase is a closed-source Backend as a Service that restricts access to the underlying details and limits the ability to make custom modifications. In contrast, Juno is fully [open-source](https://github.com/junobuild/), providing transparency and the flexibility to customize as needed. #### Pricing Firebase follows a usage-based pricing model, where costs are calculated based on factors like request volume and data storage. The absence of a cap-setting option is a cause for concern, as unexpected spikes in usage can result in substantial expenses. In contrast, Juno takes a different approach. Developers pre-charge their modules with [cycles](/docs/terminology.md#cycles), which are then utilized to cover computation and memory usage. This mechanism eliminates the risk of encountering unexpected financial burdens due to unforeseen usage surges. ### Do you have a library for \[some other language\]? We officially support [JavaScript](/docs/setup-the-sdk.md) for anything frontend. Extending serverless functions is done in [Rust](/docs/build/functions/development/rust.md) or [TypeScript](/docs/build/functions/development/typescript.md). Community-supported libraries and contributions are warmly welcomed. ### Where can I find resources about Juno? The [documentation](/docs/intro.md) is a great starting point to explore Juno. Additionally, the [blog](https://juno.build/blog) provides insightful tutorials for various frameworks. You can also check out the [guides](/docs/category/guides.md), which feature examples to help you get started. --- Do you have more questions or need further assistance? Feel free to reach out to us on [Discord](https://discord.gg/wHZ57Z2RAG) or [Twitter](https://twitter.com/junobuild). We're here to help! --- # Source: https://juno.build/docs/examples/frontend.md # Frontend Build full apps with Juno using your preferred frontend framework. These examples cover everything from auth to data handling with React, SvelteKit, Angular, Next.js, and more. [## 📄️ Next.js A fullstack note-taking app built with Next.js, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/nextjs.md) [## 📄️ React TypeScript A fullstack note-taking app built with React, TypeScript, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/react-typescript.md) [## 📄️ React JavaScript A fullstack note-taking app built with React, JavaScript, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/react-javascript.md) [## 📄️ Vue A fullstack note-taking app built with Vue, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/vue.md) [## 📄️ SvelteKit A fullstack note-taking app built with SvelteKit, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/sveltekit.md) [## 📄️ Angular A fullstack note-taking app built with Angular, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/angular.md) [## 📄️ Vanilla JavaScript A fullstack note-taking app built with vanilla JavaScript, and Tailwind CSS using Juno for authentication, data, and file storage.](/docs/examples/frontend/vanilla-javascript.md) --- # Source: https://juno.build/docs/reference/functions.md # Source: https://juno.build/docs/examples/functions.md # Functions Write serverless backend logic for your app using TypeScript or Rust. These examples show how to use hooks, assertions, and common function patterns on Juno. [## 🗃️ Rust 4 items](/docs/examples/functions/rust.md) [## 🗃️ TypeScript 3 items](/docs/examples/functions/typescript.md) --- # Source: https://juno.build/docs/examples/functions/rust/generating-assets.md # Generating Assets with Rust Serverless Functions This example demonstrates how to use **Rust serverless functions** to dynamically generate and store assets in **Juno Storage** from a **Satellite**. In this example, the generated assets are JSON files. Each time a note is added through the frontend, the Satellite saves the note as an individual JSON file and updates a list of all notes as another JSON file. This pattern is useful for exposing structured, queryable data as static assets — consumable by your frontend or external services. You can browse the source code here: [github.com/junobuild/examples/tree/main/functions/rust/json](https://github.com/junobuild/examples/tree/main/functions/rust/json) --- ## Folder Structure ``` rust/json/├── src/│ ├── satellite/ # Rust Satellite serverless function│ │ ├── src/│ │ │ ├── lib.rs # Main Rust logic for Satellite│ │ │ └── generators.rs# Helper logic for JSON generation/storage│ │ ├── satellite.did # Candid interface definition│ │ └── Cargo.toml # Rust package config│ ├── declarations/ # TypeScript declarations for Satellite│ ├── lib/ # Svelte frontend components, stores, types│ ├── routes/ # SvelteKit route files│ ├── app.html # Svelte app entry│ └── app.css # Styles├── juno.config.ts # Juno Satellite configuration├── package.json # Frontend dependencies└── ... ``` --- ## Key Features * **Serverless JSON Generation**: Demonstrates how to generate and store JSON files in Storage from Rust serverless functions. * **Automatic List Updates**: Each note addition updates both the individual note JSON and a list of all notes as JSON. * **Integration with Juno Storage**: Uses Juno's Storage API to expose JSON assets on the web. * **Minimal SvelteKit UI**: A simple SvelteKit frontend is included to test and demonstrate the logic. --- ## Main Backend Components * **src/satellite/src/lib.rs**: The entry point for the Satellite serverless function. Triggers JSON generation and list update on document set. * **src/satellite/src/generators.rs**: Helper logic for encoding notes and lists as JSON and storing them as assets. * **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function. --- ## Example: Generating and Storing JSON Here’s the actual Rust logic from `lib.rs` and `generators.rs`: ``` // src/satellite/src/lib.rsmod generators;use crate::generators::{generate_list_of_notes, generate_note};use junobuild_macros::on_set_doc;use junobuild_satellite::{include_satellite, OnSetDocContext};/// Hook triggered whenever a document is set (e.g., added or updated)./// This example:/// - Stores the updated document as an individual JSON file in Storage/// - Updates a list of all note filenames as a separate JSON file#[on_set_doc]async fn on_set_doc(context: OnSetDocContext) -> Result<(), String> { ic_cdk::print("Let's go!"); // Save the current note as a JSON asset generate_note(&context.data.key, &context.data.data.after)?; // Regenerate the list of notes as a JSON array generate_list_of_notes()?; Ok(())}// Boilerplate macro to include the all Satellite runtimeinclude_satellite!(); ``` ``` // src/satellite/src/generators.rsuse junobuild_satellite::{list_assets_store, set_asset_handler, Doc};use junobuild_shared::types::core::Key;use junobuild_shared::types::list::ListParams;use junobuild_storage::http::types::HeaderField;use junobuild_storage::types::store::AssetKey;use junobuild_utils::{decode_doc_data, encode_doc_data_to_string};use serde::{Deserialize, Serialize};/// Represents the expected shape of a note stored in the Datastore#[derive(Serialize, Deserialize)]struct Note { text: String, url: Option,}/// Encodes a note document as JSON and stores it as a `.json` file in Storagepub fn generate_note(key: &Key, doc: &Doc) -> Result<(), String> { let note: Note = decode_doc_data(&doc.data)?; let json = encode_doc_data_to_string(¬e)?; let name = format!("{}.json", key); insert_asset(&name, &json)}const STORAGE_COLLECTION: &str = "json";/// Lists all assets in the `json` collection and stores their filenames/// in a `notes.json` file — a JSON array of all note filenamespub fn generate_list_of_notes() -> Result<(), String> { let params: ListParams = ListParams { matcher: None, paginate: None, order: None, owner: None, }; let result = list_assets_store(ic_cdk::id(), STORAGE_COLLECTION, ¶ms)?; // Extract the full paths of all assets in the collection let list_of_keys: Vec = result .items .iter() .map(|(_, asset)| asset.key.full_path.clone()) .collect(); let json = encode_doc_data_to_string(&list_of_keys)?; let name = "notes.json".to_string(); insert_asset(&name, &json)?; Ok(())}/// Stores a given string as an asset in the `json` collectionfn insert_asset(name: &String, json: &String) -> Result<(), String> { ic_cdk::print(format!("Json: {} {}", name, json)); let full_path = format!("/{}/{}", STORAGE_COLLECTION, name); let key: AssetKey = AssetKey { name: name.clone(), full_path: full_path.clone(), token: None, collection: STORAGE_COLLECTION.to_string(), owner: ic_cdk::id(), description: None, }; // Set appropriate headers for serving JSON let headers = vec![HeaderField( "content-type".to_string(), "application/json".to_string(), )]; // Upload asset to Juno Storage set_asset_handler(&key, &json.as_bytes().to_vec(), &headers)?; ic_cdk::print(format!( "Asset saved in Storage: http://{}.localhost:5987{}", ic_cdk::id(), full_path )); Ok(())} ``` **Explanation:** * When a note is added or updated, the `on_set_doc` hook is triggered. * The note is encoded as JSON and stored as an asset in the `json` collection. * A list of all note asset paths is also generated and stored as `notes.json`. * These JSON assets are accessible via the Storage API and can be fetched by the frontend or other clients. --- ## How to Run 1. **Clone the repo**: ``` git clone https://github.com/junobuild/examplescd rust/hooks ``` 2. **Install dependencies**: ``` npm install ``` 3. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 4. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 5. **Create required collections**: * `demo` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `json` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 6. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` 7. **Build the serverless functions** (in a separate terminal): ``` juno functions build ``` The emulator will automatically upgrade your Satellite and live reload the changes. --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.ts` with the production Satellite ID. * Build and deploy the frontend: ``` npm run buildjuno hosting deploy ``` * Build and upgrade the serverless functions: ``` juno functions buildjuno functions upgrade ``` --- ## Notes * This example focuses on the Rust serverless function. The frontend is intentionally minimal and included only for demonstration. * Use this project as a starting point for generate dynamic assets using Juno and Rust. --- ## References * [Serverless Functions Guide](/docs/guides/rust.md) * [Functions Development](/docs/build/functions.md) * [Rust SDK Reference](/docs/reference/functions/rust/sdk.md) * [Rust Utils Reference](/docs/reference/functions/rust/utils.md) * [Run Local Development](/docs/guides/local-development.md) * [CLI Reference](/docs/reference/cli.md) * [Configuration Reference](/docs/reference/configuration.md) * [Datastore Collections](/docs/build/datastore/collections.md) --- ## Crate Docs These crates are used to build and extend serverless functions in Rust with Juno: * [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration. * [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions. * [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling. * [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console. * [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno. --- # Source: https://juno.build/docs/build/authentication/google.md # Google Google Sign-In lets users authenticate with their existing Google account using OpenID Connect (OIDC) - a modern, secure identity standard built on top of OAuth 2.0. This provides a fast and familiar experience for users, without you having to manage passwords or credentials directly. It's the easiest way to onboard users who expect a simple, frictionless login flow that works across devices and browsers. --- ## How It Works 1. The user signs in with Google. 2. Google verifies their credentials and issues a signed OpenID Connect token. 3. Your Satellite verifies the token and its signature, and extracts the user's information (such as email or profile). 4. It then establishes a session for the user. **Note:** Google authentication is not domain-scoped. Users keep the same identity across all your apps each time you use the same Google Client ID. --- ## Configuration To enable Google authentication for your project: ### 1\. Get your Google credentials Start by creating your Google credentials. It's best to use a separate Google Cloud project for each environment (development, staging, production) so you can keep configurations clean and secure. 1. Go to the [Google Cloud Console](https://console.cloud.google.com/apis/dashboard). 2. Create a new project (or select one for your current environment). You might need to switch to your newly created project after creating it. 3. If you created a new project, configure the OAuth consent screen with information about your app. Click Configure consent screen when prompted. 4. Open **APIs & Services → Credentials**. 5. Click **Create Credentials → OAuth Client ID**. 6. Select **Web application** as the application type. Then, configure your redirect URIs. For local development, you can use something like `http://localhost:3000/auth/callback/google`. In production, use the URL that matches your deployed app, for example `https://example.com/auth/callback/google`. The exact redirect path depends on how your app handles authentication, but make sure you always set at least one redirect URI in your Google Console. **Caution:** Creating a separate OAuth 2.0 Client ID for each environment and always configuring **Authorized redirect URIs** is a must. Since the Client ID is public, leaving redirect URIs open could let attackers interfere with your authentication flow. Likewise, keeping a localhost URL alongside your production redirect is also a security risk. It's also recommended to set Authorized JavaScript origins, which will be used once FedCM (Federated Credential Management) support is added. ### 2\. Configure the provider Once your credentials are ready, you need to add your Google Client ID to your project configuration. In your `juno.config` file: ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { development: "", production: "" }, source: "dist", authentication: { google: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com" } } }}); ``` If you use different Client IDs for each environment (as recommended), you can leverage the build mode to load configuration conditionally. For example, to enable Google Sign-In only in production: ``` import { defineConfig } from "@junobuild/config";export default defineConfig(({ mode }) => ({ satellite: { ids: { development: "", production: "" }, source: "dist", ...(mode === "production" && { authentication: { google: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com" } } }) }})); ``` ### 3\. Apply the configuration Once your credentials are set in `juno.config`, you need to make sure both your frontend and your Satellite are using the correct and same Google Client ID. #### Frontend The frontend, your application, needs the Client ID to start the sign-in flow. If you are using the Juno Vite or Next.js plugin, the configuration is read automatically from `juno.config`, so you do not need to do anything. The Client ID is injected at build time. If you are not using a plugin, you need to pass the Client ID manually, either from your environment variables or directly in the sign-in call (see ([Options](#options))). #### Backend Your Satellite also needs the Client ID because it is used to validate the JWT tokens issued during the sign-in flow with the third party provider in this case Google. You can configure this in two ways: * **Through the Console:** Go to [console.juno.build](https://console.juno.build), select your Satellite, then open **Authentication → Setup** and enable **Google**. The wizard will ask for your Client ID and enable the provider. * **Through the CLI:** If you already have the CLI installed and since the Client ID has been defined in your `juno.config`, you can apply the configuration directly with: ``` juno config apply ``` By default, this applies the production configuration. You can specify another mode using `--mode` argument if needed. --- ## Sign-In Once your configuration is ready, you can let users sign in with their Google account. ``` import { signIn } from "@junobuild/core";await signIn({ google: {}}); ``` This starts the standard Google redirect flow. After the user authenticates, they should be redirected to the URL you configured as an Authorized redirect URI in the Google Cloud Console. You can pass this URL through the `redirectUrl` option. If you omit it, the current origin (`window.location.origin`) is used. ### Options Google sign-in supports a few options that let you control scopes, redirect URLs, and the overall sign-in experience. | Option | Type | Default | Description | | --- | --- | --- | --- | | `clientId` | `string` | from `juno.config` | Your Google OAuth Client ID. If not provided, it is automatically read from your project configuration using the plugins. | | `redirectUrl` | `string` | `window.location.origin` | The URL where the user is redirected after sign-in. It must match one of your authorized redirect URIs in the Google Cloud Console. | | `authScopes` | `GoogleAuthScopes` | `['openid', 'profile', 'email']` | OAuth scopes to request. Must include `openid` and at least one of `profile` or `email`. | | `loginHint` | `string` | | Optional hint such as an email address that tells Google which user is likely signing in. Helps skip the account picker for known users. | Example: ``` import { signIn } from "@junobuild/core";await signIn({ google: { redirect: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com", authScopes: ["openid", "email"], redirectUrl: "https://example.com/auth/callback/google", loginHint: "user@example.com" } }}); ``` --- ## Handling the Redirect After authentication, Google redirects the user back to your app with a signed token. You must handle that redirect on the route that matches your configured `redirectUrl`. For example, `/auth/callback/google`. ``` import { handleRedirectCallback } from "@junobuild/core";await handleRedirectCallback({ google: null }); ``` If the callback is successful, the user is signed in and a session is created. **Tip:** After handling the redirect, it's best to navigate elsewhere in your app without keeping browser history. This prevents the user from re-triggering authentication when pressing the back button. --- ## Advanced Configuration You can optionally configure how authentication sessions behave on your Satellite. These settings can be defined in your `juno.config` file and applied with `juno config apply` or adjusted directly in the Console under **Authentication → Setup**. ### Delegation The `delegation` section defines how long sessions last and which modules authenticated users are allowed to call using their active session. | Option | Type | Default | Description | | --- | --- | --- | --- | | `allowedTargets` | `PrincipalText[]` or `null` | restricted to this Satellite | List of modules (canisters on the Internet Computer) that authenticated users may call. Omit to restrict access to this Satellite only. Provide an array to allow calls only to specific targets. Set to `null` to allow calls to **any** backend (**use with caution**). | | `sessionDuration` | `bigint` | 1 day | How long a user session remains valid, expressed in **nanoseconds**. Cannot exceed 30 days. Applies only to new sessions. | Example configuration: ``` authentication: { google: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com" }, delegation: { allowedTargets: ["", ""], sessionDuration: BigInt(7 * 24 * 60 * 60 * 1_000_000_000) // 7 days }} ``` --- ## Recommendations * ⚠️ Always configure **Authorized redirect URIs** in the Google Cloud Console. * Use a separate **OAuth Client ID** for each environment (development, staging, production). * Keep your frontend and Satellite **Client IDs** in sync. * Do not leave a **localhost URI** next to production URIs in the same Client ID. * In the future, Juno will support **FedCM (Federated Credential Management)** for Google Sign-In without redirects. --- --- ## Infrastructure Overview When you enable Google Sign-In, authentication involves two systems: Google and your Satellite. Google handles the user-facing part — displaying the sign-in screen and issuing a signed OpenID Connect (OIDC) token once the user authenticates. From there, everything else runs within your Satellite container: * The Satellite verifies the token's signature. * It prepares and signs a delegation identity that represents the authenticated user session. * It creates (or retrieves) the user entry that your app can then use with Juno services such as [Datastore](/docs/build/datastore.md) and [Storage](/docs/build/storage.md). ### Token Verification OIDC tokens are signed by Google using rotating public keys (JWKS). Therefore, to verify these signatures, Satellites need access to those keys. Instead of having each Satellite perform HTTPS outcalls to Google — which would add cost and subnet load — Juno provides these keys through a shared infrastructure module called [Observatory](/docs/miscellaneous/architecture.md#observatory). Observatory regularly fetches and caches Google's public keys, ensuring that verification inside your Satellite remains fast and reliable without introducing additional overhead. This setup means your Satellite **trusts Juno** to deliver the correct, untempered, up-to-date keys. If you prefer to control this part as well, or if you want to improve redundancy in your setup while taking care of the related cost, you can spin your own Observatory instance. Reach out if you're interested in setting that up. --- # Source: https://juno.build/docs/reference/functions/typescript/ic-cdk.md # Source: https://juno.build/docs/reference/functions/rust/ic-cdk.md # IC-CDK The [Canister Development Kit](https://github.com/dfinity/cdk-rs) (`ic-cdk` or `ic_cdk`) provides core functionality for interacting with the Internet Computer in Rust. In the context of Juno, it enables your Satellite to perform low-level operations such as logging, accessing your Satellite identities, or communicating with other canisters — all essential when writing advanced serverless functions. **All features** of the IC CDK are supported in Juno Satellites. Because of this compatibility, we do not list them individually here and encourage you to consult the official documentation instead. 📦 See full documentation on [docs.rs/ic-cdk](https://docs.rs/ic-cdk/latest/ic_cdk/) **Note:** For compatibility, always use the `ic_cdk` version specified in Juno’s release notes. This ensures proper integration and avoids version mismatch issues. --- # Source: https://juno.build/docs/reference/emulator/infrastructure.md # Source: https://juno.build/docs/miscellaneous/infrastructure.md # Infrastructure Juno's infrastructure is designed to provide developers with a simple, secure, and self-contained execution environment. It blends WebAssembly container deployment with supporting services that prioritize ownership, transparency, and practical workflows. --- ## Internet Computer ![An illustration representing Juno modules living at the top of the Internet Computer](/assets/images/juno-internet-computer-905a4ce5071e12858c93525e424b9d30.webp) Juno operates on the [Internet Computer](https://internetcomputer.org/) (ICP or IC), a blockchain-based open cloud platform designed to run WebAssembly containers in a decentralized setup. Every part of the Juno platform — including your Satellites, Mission Control, Orbiters (analytics), and the platform's own services like the Console — runs as self-contained units on the IC. The Internet Computer connects independent data centers worldwide. Specialized node machines and cryptography ensure that applications run efficiently and consistently, without relying on Big Tech intermediaries. It even enables direct web content delivery from these self-contained units. While Juno relies on the Internet Computer as its primary execution layer, it avoids unnecessary complexity. Developers interact with Juno using familiar frontend and backend development workflows, without needing to manage or understand blockchain infrastructure. --- ## Supporting Infrastructure While Juno runs fully on the Internet Computer, two supporting services are maintained to handle a feature that cannot yet be decentralized — sending email notifications. * Observatory Proxy: To handle IPv6 and deduplication constraints in Internet Computer HTTPS outcalls, Juno uses an additional [proxy](https://github.com/junobuild/proxy) deployed on Google Firebase. This service may be removed in the future as the Internet Computer layer improves. * Email Notifications: Developer notifications triggered by Mission Control monitoring (such as top-up successes or failures) are sent via [Resend](https://resend.com). These services are strictly optional and exist only for this specific use case. --- # Source: https://juno.build/docs/build/authentication/internet-identity.md # Internet Identity [Internet Identity](https://identity.ic0.app) lets users authenticate securely and anonymously through a decentralized identity system built for the Internet Computer. When a user signs in with Internet Identity, they confirm their identity through the provider. If successful, a session is created automatically and the user can interact with your Satellite. Authentication with Internet Identity offers strong privacy guarantees and complete isolation between domains by design. --- ## How It Works 1. The user signs in via Internet Identity. 2. The provider issues a unique, domain-specific pseudonymous identity. 3. Your project associates that identity with the user's data in your Satellite. 4. The user can immediately start using your app - no email, passwords, or extra setup. --- --- ## Example ``` import { signIn } from "@junobuild/core";await signIn({ internet_identity: {}}); ``` This creates (or reuses) a session automatically the first time the user signs in. --- ## Options Internet Identity sign-in can be customized with options that let you control session lifetime, provider configuration, or track progress during the flow. | Option | Type | Default | Description | | --- | --- | --- | --- | | `maxTimeToLiveInNanoseconds` | `BigInt(4 * 60 * 60 * 1000 * 1000 * 1000)` | **4 hours** | Maximum lifetime of the user's session in **nanoseconds**. Once expired, the session cannot be extended. | | `windowed` | `boolean` | `true` | By default, the authentication flow is presented in a popup window on desktop that is automatically centered on the browser. This behavior can be turned off by setting the option to `false`, causing the authentication flow to happen in a separate tab instead. | | `derivationOrigin` | `string` or `URL` | | The main domain to be used to ensure your users are identified with the same public ID, regardless of which of your Satellite's URLs they use to access your application. | | `onProgress` | `(progress) => void` | | Callback for provider sign-in and user creation/loading. | | `domain` | `id.ai` or `internetcomputer.org` or `ic0.app` | `id.ai` | The domain on which to open Internet Identity. | Example with options: ``` // Sign-in with id.aiawait signIn({ internet_identity: { options: { domain: "id.ai" } }});// Sign-in with a specific session durationawait signIn({ internet_identity: { options: { maxTimeToLiveInNanoseconds: BigInt(24 * 60 * 60 * 1000 * 1000 * 1000) // 1 day } }});// Sign-in with a derivation origin and progression callbackawait signIn({ internet_identity: { options: { onProgress: ({ step, state }) => { console.log("Step:", step, "State:", state); }, derivationOrigin: "https://myapp.com" } }}); ``` --- ## Context In addition to the options above, some settings apply to flow itself. | Option | Type | Default | Description | | --- | --- | --- | --- | | `windowGuard` | `boolean` | `true` | Prevents the user from closing the current window/tab while the flow is in progress. Disabling it is discouraged. | --- ## Handling Errors If the sign-in flow encounters an error, an exception will be thrown. When a user cancels sign-in with Internet Identity (e.g., by closing the modal), the library throws a `SignInUserInterruptError`. This error indicates that the user intentionally interrupted the sign-in process, and it's generally best practice to ignore it rather than showing an error message. ``` import { signIn } from "@junobuild/core";try { await signIn({ internet_identity: {} });} catch (error: unknown) { if (error instanceof SignInUserInterruptError) { // User canceled sign-in, no need to show an error return; } // Handle other errors console.error("Sign-in failed:", error);} ``` --- ## Domain-Based Identity With Internet Identity, a user's identity is created separately for each domain. If a user signs in on two different domains, they will be treated as two separate users by default. The same applies to subdomains: signing in on `hello.com` and `www.hello.com` creates two different identities unless you configure a primary domain. The first custom domain you add in the Console is automatically set as the primary domain. You can change this setting later in Authentication, but we don't recommend it once users have already registered, since their identities are not migrated when the configuration changes. To let users keep the same identity across domains, you must also configure your frontend app to specify the main domain at sign-in. This is known as the "derivation origin" (or "alternative origins"). ### Recommendation If you're unsure which domain to use as the primary domain, here are two common approaches: * **Use your custom domain** (e.g. `mydomain.com`) if you're confident it will remain the main entry point for users. This ensures a consistent user experience - users will always see and recognize the same URL when signing in. * Alternatively, stick with **the default domain** (`{satellite-id}.icp0.io`) if: * You're still experimenting with your domain setup and might change it later. * You're not ready to commit to a long-term domain. * You plan to host multiple Satellites under different domains and don't want to tie user identity to just one. Choosing the right derivation origin early helps avoid identity issues later, but both approaches are valid depending on your goals. --- # Source: https://juno.build/docs/intro.md # Getting Started with Juno Unless you're looking to solely host your static website, the recommended way to start with Juno is by developing locally using the emulator — a production-like environment with full support for data, authentication, storage, and serverless functions. It gives you everything you need to build and test your app before deploying anything live. Here are a few solid places to go from here: * 🚀 [Start a new project](/docs/start-a-new-project.md) – Scaffold a brand new project with your favorite frontend framework. * 🔌 [Set up the SDK](/docs/setup-the-sdk.md) – Integrate Juno into an existing app. * 🧪 [Run your project locally](/docs/guides/local-development.md) – Use the emulator to build and test locally in an environment that mirrors production. * 🛰️ [Deploy with a Satellite](/docs/create-a-satellite.md) – When you're ready to go live, deploy your project to its own container. --- ## How It Works Juno is your own self-contained execution space. No DevOps. No backend boilerplate. No surprise complexity. You build your frontend using the frameworks you love — React, SvelteKit, Next.js, you name it. Need backend logic? Just drop in a serverless function written in Rust or TypeScript. Everything gets bundled into a single deployable WebAssembly (WASM) container. One artifact. One push. That's your app. It runs in an unstoppable environment that holds its entire state — data, logic, and storage. No cold starts. Your functions execute instantly. And here's the beauty of it: Juno controls nothing. It has zero access to your code, data, or infrastructure. Everything runs under your ownership. Think of it as the space between self-hosting and the serverless cloud — a reimagined model for application development. You manage your projects and supporting modules — themed around space mythology — using either a CLI or the Console UI, depending on your workflow. To strengthen this principle of non-interference, deploys and upgrades can be handled via GitHub Actions if you choose to opt in — which themselves can't start or stop your app once it's live. And during development, the environment mirrors production as closely as possible — so you're never caught by “but it worked locally.” --- ## Comparisons Wondering how Juno stacks up in the real world? Compare it to today's most popular platforms: * [vs Vercel](/docs/comparison/vs-vercel.md) * [vs Netlify](/docs/comparison/vs-netlify.md) * [vs Railway](/docs/comparison/vs-railway.md) * [vs Heroku](/docs/comparison/vs-heroku.md) * [vs Self-Hosting](/docs/comparison/vs-self-hosting.md) --- ## Further Details Learn more about the available products, from auth and data to hosting and functions. * [Authentication](/docs/build/authentication.md) * [Datastore](/docs/build/datastore.md) * [Storage](/docs/build/storage.md) * [Hosting](/docs/build/hosting.md) * [Functions](/docs/build/functions.md) * [Analytics](/docs/build/analytics.md) * [Monitoring](/docs/management/monitoring.md) * [Snapshots](/docs/management/snapshots.md) --- # Source: https://juno.build/docs/build/functions/lifecycle.md # Lifecycle Understand the full journey of Serverless Functions in Juno, from setup and development to deployment and maintenance. --- ## Initial Setup If you didn’t use a template or skipped the language selection during setup, you can run `juno functions eject` at the root of your project. This command configures your project with the appropriate setup based on your language of choice. For Rust, it includes a `Cargo.toml` and a `lib.rs` file. For TypeScript, it sets up an `index.ts` file. --- ## Developing Functions Once your project is scaffolded, you can start writing your functions. Use the CLI to build them with: ``` juno functions build ``` If you start the emulator (see chapter below) in watch mode, your functions will be rebuilt automatically on save, so you don’t need to run this command manually. --- ## Local Development For local development and testing, a sandbox environment is essential. You can establish this environment by running the CLI command `juno emulator start`. **Info:** Find more information about local development in the [documentation](/docs/guides/local-development.md). The local sandbox environment supports hot reloading. This means that the container will automatically redeploy your local Satellite each time `juno functions build` is executed and a new version is produced. If you start the emulator with the `--watch` flag, it will also rebuild your functions automatically when changes are detected. --- ## Deploying Juno offers two main ways to deploy your serverless functions, depending on whether you're working locally or integrating with a CI pipeline like GitHub Actions. --- ### 1\. Direct Deploy If you're developing locally or in another environment where the **access key has admin privileges**, you can deploy the latest build directly: ``` juno functions upgrade ``` * ✅ Skips the CDN. * ✅ Immediate deployment. * 🔐 Requires access key with upgrade permission. * 📦 Uses the default path: `./target/deploy/satellite.wasm.gz`. Optional: ``` juno functions upgrade --src ./path/to/custom-build.wasm.gz ``` --- ### 2\. With CDN + Approval Workflow If you're using CI (like GitHub Actions) or an environment where your **access key has write privileges**: #### a) Publish to CDN In your GitHub Action or script: ``` juno functions publish ``` With options: ``` juno functions publish --mode staging --src ./path/to/build.wasm.gz ``` * 📤 Uploads to the Satellite’s CDN release. * 🔐 Requires access key with **editor** role. #### b) Upgrade from CDN From your local CLI or in the Console UI, you can then upgrade. ``` juno functions upgrade --cdn ``` * 🔎 Interactively selects the WASM version from the published CDN. * 🧾 Only deploys with a key that has **upgrade** rights. * 🕵️ If your key is **submit-only**, the change will wait for approval in the Console UI or CLI. --- ### 3\. Optional Approval Flow If you're using CI (like GitHub Actions) or an environment where your **access key has submit privileges** — meaning it cannot directly modify or write data — you can follow a workflow that requires manual approval before deployment. ``` juno functions publish --no-apply ``` Then the published release: * Becomes a **pending change**. * Must be **reviewed and applied** manually. Apply the change either in the Console UI or directly using the CLI. #### 📜 List submitted changes ``` juno changes list ``` #### ✅ Apply a specific change ``` juno changes apply --id ``` Once applied, the Satellite can then be upgraded in the CLI or respectively in the Console UI using: ``` juno functions upgrade --cdn-path ``` --- ## Summary A quick reference for the most common CLI commands and deployment workflows when working with serverless functions in Juno. ### 🛠️ Common CLI Commands | Command(s) | Scenario | | --- | --- | | `juno functions eject` | Initializes your project for writing serverless functions. | | `juno emulator start` | Starts the emulator. | | `juno functions build` | Compiles your custom Satellite's code. Changes are automatically redeployed locally. | ### 🚀 Deployment Scenarios | Command(s) | Scenario | | --- | --- | | `juno functions upgrade` | Upgrades your serverless functions immediatly. | | `juno functions upgrade --src ./path/to/custom-build.wasm.gz` | Use a custom WASM path to upgrade. | | `juno functions publish` in CI → `juno functions upgrade --cdn` in CLI or Console UI | CI/CD with write access. | | `juno functions publish --no-apply` in CI → `juno changes apply` → `juno functions upgrade --cdn-path ...` | CI/CD with submit-only access. | | `juno functions publish --mode staging` | CI/CD using staging environment. | --- # Source: https://juno.build/docs/guides/local-development.md # Local Development Juno offers something most platforms don't: a full local development environment that closely mirrors production. ## TL;DR | What | How | | --- | --- | | Runtime supported | Docker or Podman | | Start emulator | `juno emulator start` | | Stop emulator | `juno emulator stop` | | Console UI URL | [http://localhost:5866](http://localhost:5866) | --- ## What the Emulator Includes When you develop locally, you're running an emulator that includes the well known infrastructure services — including the actual administration Console UI. This enables: * A development experience that mirrors mainnet, helping you build with confidence * A smooth dev loop, from prototype to deployment * A unique way to build, debug, and validate smart contract logic and frontend behavior — all in one place ![A screenshot of the DEV Console UI login screen](/assets/images/login-22bd49b1624f8c4c89c5c1e33b2fc70c.png) --- ## Before you begin The emulator is a self-contained local environment that runs in a container managed entirely by Juno — using either [Docker](https://www.docker.com/) or [Podman](https://podman.io/) under the hood. Make sure your preferred runtime is installed on your machine: * [Docker: Windows](https://docs.docker.com/desktop/install/windows-install/) * [Docker: macOS](https://docs.docker.com/desktop/install/mac-install/) * [Docker: Linux](https://docs.docker.com/desktop/install/linux-install/) * [Podman: Installation guide](https://podman.io/getting-started/installation) **Important:** For MacBooks with M-series processors, if you aim to use **Docker**, it is important to install Docker Desktop **version 4.25.0 or later**, ideally the latest available version. For **Podman**, we are not aware of any particular version requirements at this time. --- ## Getting Started To run the emulator for local development, you need to have the Juno CLI installed. If you haven't installed it yet, run: * npm * yarn * pnpm ``` npm i -g @junobuild/cli ``` ``` yarn global add @junobuild/cli ``` ``` pnpm add -g @junobuild/cli ``` Then, in your project folder, start the local emulator with: ``` juno emulator start ``` This will launch the emulator along with all the services needed to develop your project. We recommend running this in a dedicated terminal window or tab, while your frontend project (e.g. using Vite or Next.js) runs separately using npm run dev or similar. To stop the emulator, run: ``` juno emulator stop ``` **Note:** While you could technically start the emulator using `docker run` or `podman run`, we recommend using the Juno CLI to manage the emulator lifecycle. It handles important checks, sets the correct configuration, and ensures everything runs as expected. --- ## Available Images Juno provides two local environments. Most developers should start with **Skylab**, but Satellite is available for advanced or specialized workflows. ### 🧪 Skylab: Full Local Stack (Recommended) The `junobuild/skylab` image is the default and recommended environment. It mirrors the production stack and includes everything needed for end-to-end development. Use it for the full experience, including the Console UI and supporting infrastructure. ### ⚙️ Satellite: Minimal Setup The `junobuild/satellite` image is a lightweight alternative that runs a single Satellite. It skips the Console UI and supporting infrastructure. Use it when you need a faster, minimal setup focused on CI pipelines or automated testing. **Note:** The default (auto-deployed) Satellite is available with a predefined canister ID `jx5yt-yyaaa-aaaal-abzbq-cai`. ### 📊 Feature Comparison The table below shows which modules are available in each image and helps clarify what's included when running locally with Skylab or Satellite. | Module | Skylab | Satellite | | --- | --- | --- | | Console (Backend) | ✅ | ❌ | | Console (UI) | ✅ | ❌ | | Create Satellites / Orbiters via Console UI | ✅ | ❌ | | Default (auto-deployed) Satellite | ❌ | ✅ | | Observatory | ✅ | ❌ | Likewise, not all services are mounted by default - but they can be turned on (or off). | Service | Skylab | Satellite | | --- | --- | --- | | Internet Identity | ✅ | ✅ | | ICP Ledger | ✅ | ✅ | | ICP Index | ✅ | ✅ | | NNS Governance | ✅ | ➖ | | Cycles Minting (CMC) | ✅ | ➖ | | Cycles Ledger | ✅ | ➖ | | Cycles Index | ✅ | ➖ | | Registry | ➖ | ➖ | | SNS | ➖ | ➖ | | NNS-dapp | ➖ | ➖ | --- ## Console UI When using the `junobuild/skylab` image, the Console UI becomes available by default at: ``` http://localhost:5866/ ``` Once the emulator is running (`juno emulator start`), visit this URL in your browser to explore the Console — where you can create and manage Satellites, and explore features like Datastore, Authentication, Storage, and more. --- ## Hot Reload The local container supports live reloading. When you modify your [configuration](/docs/reference/emulator/satellite.md#configuration) or build custom [Functions](/docs/build/functions.md) to enhance Juno's capabilities with serverless features, those changes will be automatically redeployed. --- ## Configuration Options To customize the behavior of the local emulator—such as changing ports, setting a persistent volume name, or overriding the runner image — refer to the [Emulator Configuration](/docs/reference/configuration.md#emulator-configuration) section. There you'll find detailed information about available options including: * ⚙️ Runner settings (e.g. image, platform, volume) * 🔌 Custom port mappings * 📁 Shared folders and hot reloading * 🧪 CI and test environment tips --- ## Usage During local development - `npm run dev` - your app connects to the local emulator (container) by default — no extra configuration needed. ### Automatic Configuration (Recommended) The recommended way to connect your app to the local container run in the emulator or any environment is by using the [plugins](/docs/reference/plugins.md). They automatically resolve the Satellite ID and other environment variables and handle initialization for you. ### Manual Initialization If you're not using a plugin and are initializing Juno manually, here's how to configure it to use the local container: ``` import { initSatellite } from "@junobuild/core";const container = import.meta.env.DEV === true;await initSatellite({ satelliteId: container ? "jx5yt-yyaaa-aaaal-abzbq-cai" : "aaaaa-bbbbb-ccccc-ddddd-cai", container}); ``` ### Opt-out The SDK automatically uses the emulator in local development. If you want to disable that behavior and connect directly to a remote canister (e.g. in CI or production testing), you can do: ``` await initSatellite({ satelliteId: "aaaaa-bbbbb-ccccc-ddddd-cai", container: false}); ``` --- ## Administration The admin server running on port `5999` provides a variety of internal management. Below are some tips and example scripts to make use of this little server. ### Get Cycles If you're using the full environment, the Console UI includes a "Get Cycles" button in the wallet. It's a quick way to get Cycles out of the box. ![A screenshot of the wallet with the Get Cycles call to action of Console UI in dev mode](/assets/images/wallet-2337251849c790b75db91656c65e61d5.png) You might want to transfer some Cycles from the ledger to a specified principal, which can be particularly useful when you're just getting started developing your app and no users currently own Cycles. This can be achieved by querying: ``` http://localhost:5999/ledger/transfer/?to=$PRINCIPAL&ledgerId=um5iw-rqaaa-aaaaq-qaaba-cai&amount330000000000000 ``` For example, you can use the following script: ``` #!/usr/bin/env bash# Check if a principal is passed as an argument; otherwise, prompt for itif [ -z "$1" ]; then read -r -p "Enter the Wallet ID (owner account, principal): " PRINCIPALelse PRINCIPAL=$1fi# Make a transfer request to the admin servercurl "http://localhost:5999/ledger/transfer/?to=$PRINCIPAL" ``` --- # Source: https://juno.build/docs/build/functions/logs.md # Logs Writing and viewing logs is a crucial tool for debugging and monitoring your code. Serverless Functions offer you the option to utilize loggers to report status effectively. ![A screenshot of the Juno's Console feature to browse logs](/assets/images/functions-754bffa459e2345077924846bf09ef3d.webp) --- ## Native Logging The Internet Computer provides a native, simple logging system where logs are persisted within the state up to a maximum size of 4 KiB. **Note:** If new logs exceed the 4 KiB limit, the oldest entries will be removed. Logs persist across Satellite upgrades. These logs are the preferred method for writing and viewing logs, as they are more efficient and cost-effective compared to the custom solution below. They also persist regardless of whether the update call succeeds or fails. However, native logs do not yet support log levels, that's why all entries will appear as "Error" in the Juno Console. Any printed or trapped messages using the `ic_cdk` crate are automatically collected as logs. ### Example Usage ``` fn log() { ic_cdk::print("This is a log entry."); ic_cdk::trap("There was an error.");} ``` --- ## Custom Logging Custom logging provides a flexible way to track and debug function executions within your Satellite if the native logging does not answer your needs. ### How does it work? Logs are stored in stable memory, accommodating up to 100 entries. Once this limit is reached, the oldest entry is discarded. It's important to note that since logs are saved in memory, your hooks should return a success—meaning they should not trap—otherwise, the information cannot be preserved. ### Available loggers | Logger | Level | Description | | --- | --- | --- | | `log` | Info | Logs a message. | | `log_with_data` | Info | Logs a message with additional serialized data. | | `info` | Info | Logs an informational message. | | `info_with_data` | Info | Logs an informational message with additional serialized data. | | `debug` | Debug | Logs an debug-level message. | | `debug_with_data` | Debug | Logs a debug-level message with additional serialized data. | | `warn` | Warning | Logs a warning message. | | `warn_with_data` | Warning | Logs a warning message with additional serialized data. | | `error` | Error | Logs an error message. | | `error_with_data` | Error | Logs an error message with additional serialized data. | --- # Source: https://juno.build/docs/build/authentication/management.md # Management This page provides an overview of the administrative functions available in the Juno Console related to user management. --- ## Banning Users The built-in authentication feature allows developers to ban or unban users within their dapps. When a user is banned, they lose access to key services such as Datastore and Storage, preventing them from creating, updating, or deleting any data. This feature helps developers prevent misuse, spam, or abusive behavior in their applications. **Note:** A ban is not a deletion. The user's authentication entry remains in the system, and they can be unbanned at any time. ### How to Ban a User To ban a user, follow these steps: * Navigate to the Authentication section in the [console](https://console.juno.build). * Find the user you want to ban in the users' table. * Click on the Active / Ban button at the start of the row. * Confirm the action. Once banned, the user will not be able to sign in, create, update, or delete data in Datastore or Storage. ![A screenshot of the Juno Console's Authentication section, displaying the user management interface with options to ban or unban users](/assets/images/user-management-ban-90535848bf31b97659d5fecd4e4d54f1.webp) --- ## Setup The Authentication tab in the Console (or the CLI config) lets you customize how users sign in to your app and who's allowed to access it. Here are the available options: --- ### Main Domain ("Derivation Origin") This setting helps you control how users are identified when signing in with Internet Identity. It makes sure users get the same identity across different domains or subdomains of your app. For example, if you set it to "hello.com", a user signing in at [https://hello.com](https://hello.com) will receive the same identifier (principal) as when signing in at [https://www.hello.com](https://www.hello.com). In other words, the user will be recognized as the same person. This is useful because, by design, it creates a different identity for each domain to protect user privacy and prevent tracking. Use this if your app runs on multiple subdomains and you want a consistent user experience. --- ### Max Updates Per Minute This lets you limit how many new users can sign up per minute. It's helpful to prevent abuse or unexpected spikes (like bots flooding your app). For example, setting this to `10` means only `10` new users can be created per minute. Default is `100`. --- ### Allowed Callers This option gives you full control over who's allowed to use your app. If you enable this, only the identities you list (in user key, format, like `bj4r4-5cdop-...`) will be allowed to sign in or use any features like Datastore or Storage. * If someone's not on the list, they can't even register. * If they are, they can use the app just like any other user (unless they're banned). Use this if you want to limit access to a private group — for example, for internal testing or early access users. #### How to Get the User Identities There are two common ways to manage the list of authorized users: 1. After sign-in You can share your app link with a few users, let them sign in, and then add their keys to the authorized list. The user table will show their identity once they've signed in at least once. 2. Before sign-in If you want to block all sign-ins except for those explicitly allowed before hand, start by adding your own developer ID (shown in the Console) to the list. This activates the restriction: once at least one identity is listed, only those identities can sign in. If the list is empty, then everyone can sign in. You can then share the app link with others. When they attempt to sign in and are blocked, you can show a message that displays their user key (e.g. using the `unsafeIdentity` function from `@junobuild/core`). They can send you their key, and you can add them to the list manually to grant access. --- # Source: https://juno.build/docs/guides/manual-deployment.md # Manual Deployment We recommend using [GitHub Actions](/docs/guides/github-actions.md) for automated and efficient deployments. However, this guide walks you through manually deploying your app using the Juno CLI, covering the setup, build, and deployment process to your Juno Satellite. --- ## 1\. Install Juno CLI Install the Juno command line interface by executing the following command in your terminal: * npm * yarn * pnpm ``` npm i -g @junobuild/cli ``` ``` yarn global add @junobuild/cli ``` ``` pnpm add -g @junobuild/cli ``` --- ## 2\. Initialization Once the CLI is set up, initialize your project by running: ``` juno config init ``` This command generates a configuration file and prompts you to log in to your Satellite from the terminal to authenticate your device. Upon execution, Juno’s Console will open in your browser, where you’ll be asked to grant permissions for your modules. These include Mission Control (your wallet), Satellite(s), and Analytics, allowing secure access from your machine. **Info:** If the login process opens in a different browser than the one where you're already signed into, simply copy the URL and paste it into your authenticated browser to continue. This can occur if you've signed into the Juno Console in a browser other than your system's default. --- ## 3\. Deploy Your Project You can use the CLI to manually deploy different parts of your app: * 🪄 Deploy frontend assets to your Satellite. Learn how. * 🛠️ Build, publish and upgrade serverless functions (TypeScript or Rust). Learn how. --- ### a) 🪄 Deploy Frontend Assets Get your app ready for deployment: * npm * yarn * pnpm ``` npm run build ``` ``` yarn build ``` ``` pnpm build ``` Deploy your application or website by running the following command from your project’s root folder: ``` juno hosting deploy ``` **Tip:** When prompted for the name or path of the folder containing your built dapp files, provide the appropriate folder name for your framework, such as `build` (SvelteKit), `out` (Next.js), or `dist` (React, Astro, or Vue). Wait for the deploy to complete. Once uploaded, it will be live on your Juno Satellite and accessible on the web. --- ### b) 🛠️ Build, Publish, and Upgrade Serverless Functions To build and deploy your serverless functions written in TypeScript or Rust, you can use the CLI. ``` juno functions buildjuno functions publishjuno functions upgrade ``` * Use publish `--no-apply` if your access key only has a **submit** role and cannot directly upgrade. * You can then approve and apply the change using the CLI (with another key) or Console UI. For a full overview of the serverless lifecycle—including setup, development, local testing, publishing, approvals, and upgrades — see the Serverless Functions Lifecycle guide. --- # Source: https://juno.build/docs/miscellaneous/memory.md # Memory This page explains how memory works conceptually and how you can monitor its usage through the Console. --- ## General Memory Usage Every module — whether it's a [satellite](/docs/terminology.md#satellite), [orbiter](/docs/terminology.md#orbiter), or your [mission control](/docs/terminology.md#mission-control) — consumes memory in multiple ways. Some of that memory is directly controlled by your code, like the data you store in your [datastore](/docs/build/datastore.md) or [storage](/docs/build/storage.md). Other parts are more structural: global variables, the WASM binary (the container code itself), snapshots, and even system metadata contribute to your overall memory footprint. To help you understand and optimize memory usage, the Console displays a detailed breakdown under each module's overview tab. These metrics are especially helpful for staying within limits, controlling costs, and avoiding issues during upgrades. ### Metrics | Metric | Description | Keyword | | --- | --- | --- | | `wasm_memory_size` | Heap memory used by the module to save data. | Heap | | `stable_memory_size` | Stable memory used by the module to save data. | Stable | | `wasm_binary_size` | Size of the deployed container's code — specifically, the size of the installed gzipped WASM binary. | Code | | `wasm_chunk_store_size` | Memory used for storing chunks of the code when installing large containers (WASM > 2 MB). Used only in Mission Control. | Chunks | | `custom_sections_size` | Memory used to store metadata like version info or API definitions, stored in the container WASM binary's custom sections. | Metadata | | `canister_history_size` | Memory used by the module's history (e.g. creation, installation, upgrade, or controller changes). | History | | `snapshots_size` | Memory consumed by snapshots created for the module. | Snapshots | --- ## Satellite A [satellite](/docs/terminology.md#satellite) can store data using two types of memory: `heap` and `stable`. Both are forms of random-access memory that exist only while the satellite is active. As an analogy, `heap` is like RAM in a computer, while `stable` is more like ROM. ### In a nutshell `Heap` memory offers the best performance for accessing data, both for reading and writing. However, it has a limited capacity in terms of the space it can occupy, with a max of 1 GB. On the other hand, `stable` memory has a higher memory threshold with a maximum limit of 500 GB minus the heap size, allowing it to store more data in terms of size. However, it is slightly slower. Additionally, `heap` memory needs to be deserialized and serialized each time you upgrade the module's code. This process becomes heavier as the heap memory size grows. On the contrary, `stable` memory doesn't require processing during an upgrade. However, the data it contains needs to be deserialized and serialized each time it is accessed, which can make its usage more costly. ### Recommendations There are no strict rules governing the choice of memory type for your use case. Ultimately, the decision depends on your patterns and strategy. That said, **stable memory is strongly recommended** for the vast majority of data storage scenarios. Why? Because: * It allows you to offload large or infrequently accessed data from the limited heap space. * It avoids serialization overhead during upgrades. * It supports much larger data volumes. In contrast, `heap` memory is best reserved for: * Serving your frontend assets (HTML, JS, images, etc.). * Small, ephemeral datasets that benefit from fast access and won't push the 1 GB heap limit. This is why both the [datastore](/docs/build/datastore.md) and [storage](/docs/build/storage.md) support both memory types — but default to `stable`, which is also the **recommended** option. ### Default usage By default, the memory model aligns with these best practices: * Your dapp's frontend assets — everything deployed using `juno hosting deploy` — are stored in `heap` memory. * In contrast, your users (as of Satellite version 0.0.16) and the [analytics](/docs/build/analytics.md) data are saved within `stable` memory. ### Summary | Aspect | Heap Memory | Stable Memory | | --- | --- | --- | | **Capacity** | Max 1 GB | Max 500 GB (minus heap size) | | **Performance** | Fast for read and write operations | Slightly slower | | **Cost** | Lower cost | Higher cost (~20x) | | **Upgrades** | Data must be deserialized/serialized during upgrades | Data are not processed during upgrades | | **Usage** | Suitable for small or frequently accessed data | Suitable for large or less frequently accessed data | | **Recommendation** | Use sparingly to avoid upgrade friction and size limits | Default and recommended for most use cases | --- ## Behavior When discussing memory, it's important to understand how WebAssembly (WASM) memory behaves at a lower level. ### Memory Growth and Reuse WASM memory can **grow**, but it **cannot shrink**. This behavior is **not specific to Juno** — it's part of the WASM standard and applies across all platforms using WASM. * Once the memory size increases (e.g. due to allocations or data structure growth), the total allocated memory **remains fixed at the new size**, even if you later free or remove data. * However, memory that is no longer in use is **internally reused or reallocated**, so your container is not constantly allocating more memory unless needed. ### What to Expect * It's normal to see your module's reported memory usage increase over time and **not decrease**, even after deletions or optimizations. * The **only time this memory resets** is during an **upgrade**, which reinitializes the heap with the new WASM binary and runtime state. * As a result, a growing memory footprint isn't necessarily a problem — but it's worth monitoring, particularly when it comes to the heap, which should not exceed the 1 GB limit. ### Best Practices * As recommended in this documentation, **use stable memory** for large or infrequently accessed data to reduce heap pressure and avoid excessive memory growth. In other words, try to avoid using heap memory for anything beyond serving your frontend app. * **Keep your heap size well below the 1 GB limit**, especially if you expect frequent upgrades or manage large in-memory state. * **Ensure reproducible builds** of your frontend application. On deploy, only actual changes should be pushed to avoid unintentionally bloating memory usage. ([Why this matters.](#ensure-your-frontend-build-is-reproducible)) * Use the Console UI's available tools and metrics to track memory usage and growth patterns over time. --- ## Exceeding the Heap Memory Limit Every Satellite, and generally any module on Juno, starts with a default heap memory limit of 1 GB. While you can increase this limit in the settings, it's not recommended to go beyond it, as it may cause issues when upgrading your module. The heap includes a bit of metadata, any collections you've created in Datastore and Storage (where using stable memory is advised), and the assets of your frontend application. If you're deploying a really large application (>1 GB) or frequently pushing updates to an application that isn’t reproducible, your heap memory usage can grow unexpectedly and eventually hit the limit. When that happens, your next deployment or update might fail to prevent exceeding the limit, which could lead to issues with your module. ``` Request ID: d7be9..bfcb8 Reject code: 5 Reject text: Error from Canister aaaaa-bbbbb-ccccc-ddddd-cai: Canister exceeded its current Wasm memory limit of 1073741824 bytes. The peak Wasm memory usage was 1073872896 bytes. If the canister reaches 4GiB, then it may stop functioning and may become unrecoverable. Please reach out to the canister owner to investigate the reason for the increased memory usage. It might be necessary to move data from the Wasm memory to the stable memory. If such high Wasm memory usage is expected and safe, then the developer can increase the Wasm memory limit in the canister settings..Try checking the canister for a possible memory leak or modifying it to use more stable memory instead of Wasm memory. See documentation: https://internetcomputer.org/docs/current/references/execution-errors#wasm-memory-limit-exceeded ``` ### Preventing Heap Memory Issues To avoid running into memory limits, it's important to monitor memory usage and follow two key best practices: #### Ensure Your Frontend Build is Reproducible When building your frontend (e.g. with `npm run build`), the output should be identical to the previous build if no changes were made. Why does this help? When you deploy your application, Juno does not clear existing files—it only adds new ones. To optimize this process, Juno compares the names and content (hash values) of all files with those already uploaded. If a file hasn't changed, it is skipped, reducing unnecessary memory usage and saving cycles. If your build output isn’t reproducible, every deployment could introduce slightly different files, even if nothing has changed in your code. Over time, this would lead to unnecessary file accumulation, increasing heap memory usage and eventually causing issues. #### Resolving Heap Memory Issues There are different ways to resolve this issue, and the best approach depends on the features you're using. If you're using Datastore and Storage, we need to find a solution that prevents data loss. If you're only hosting a website, the steps to fix the issue will be much simpler. In any case, the best course of action is to reach out so we can assess your situation and find a tailored solution together. --- ## Resources * [Measure different collection libraries written in Rust](https://dfinity.github.io/canister-profiling/collections/) * [Question about freeing/shrinking memory in WebAssembly design](https://github.com/WebAssembly/design/issues/1300) --- # Source: https://juno.build/docs/management/monitoring.md # Monitoring Keeping your modules running smoothly is essential for any application. The monitoring feature ensures your modules — Satellites and Orbiter (Analytics) — stay operational by automatically refilling cycles when they run low. This helps prevent unexpected downtime, allowing you to focus on building and growing your product without worrying about cycle balances. ![A screenshot of the monitoring overview within Juno Console](/assets/images/monitoring-dashboard-caf86757b1501c3fe41cbae3cffa3ff3.webp) --- ## Features * **Cycle refilling**: Monitored modules are automatically topped up when their balance falls below what's needed to stay active. * **Self-Monitoring**: The monitoring monitors itself to maintain sufficient cycles, with full control remaining in your hands at all times. * **Hourly Checks**: The system evaluates balances once an hour. * **Automatic ICP Conversion**: Can mint new cycles from the ICP in your wallet, ensuring your modules stay adequately funded. --- ## Why Enable Monitoring? When a container runs out of [cycles](/docs/terminology.md#cycles) on the [Internet Computer](https://internetcomputer.org), it stops functioning, which can disrupt your application or service. Enabling monitoring provides peace of mind by automating the management of cycles, ensuring your modules are always ready to perform. It also saves a little time by eliminating the need for manual top-ups. It's important to note that if your modules run out of cycles, they will enter a grace period. During this time, the module stops working but can still be restored. If no action is taken, the module eventually gets deleted, resulting in the permanent loss of its data and functionality. --- ## How does it work? Monitoring runs hourly within a dedicated service called Mission Control, which acts as the central hub for managing all monitored modules. The process follows these steps: --- ### Periodic Balance Checks Your Mission Control evaluates the cycle balances of all modules you've enabled for monitoring, including itself. Monitoring cannot be enabled without also observing Mission Control (your wallet), as it serves as the source for auto-refills. The system compares the cycle balance of each module (and Mission Control) against the sum of the grace period requirement and the trigger threshold you've configured. For example: * Grace Period Requirement: 0.5T Cycles * Trigger Required Amount: 0.5 T Cycles * \=> Total Required: 1.0T Cycles * Current Balance: 0.8 T Cycles Since the balance is 0.2 T Cycles below the required amount in this example, the system will attempt an auto-refill. --- ### Auto Refilling When a module is eligible for refill, Mission Control attempts to top it up by following these rules: #### a. Topping up from Mission Control's cycles If Mission Control has enough cycles above its own required amount, it uses them to refill the module. For example: * Mission Control Balance: 10 T Cycles * Mission Control Required Amount: 3 T Cycles * Module Required Amount: 1 T Cycles * Current Module Balance: 0.5 T Cycles * Top-Up Amount (Configured): 2 T Cycles In this case, Mission Control deducts 2 T Cycles to top up the module, leaving: * Mission Control Balance: 8 T Cycles * Module Balance: 2.5 T Cycles #### b. When Mission Control cannot top up If Mission Control's balance is below its own required amount, it cannot top up the module. For example: * Mission Control Balance: 10 T Cycles * Mission Control Required Amount: 12 T Cycles In this example, Mission Control's balance is already below its own requirement; therefore, no top-up can be performed unless it also holds ICP. #### c. Minting Cycles from ICP If Mission Control's balance is insufficient but it holds ICP, it can mint cycles to refill the module. For example: * Mission Control Balance: 10 T Cycles * Mission Control Required Amount: 12 T Cycles * ICP Balance: 1 ICP Mission Control uses part of its ICP to mint cycles: * Mission Control Balance (after minting): 10 T Cycles * Module Balance: 2.5 T Cycles * ICP Balance (after minting): ~0.75 ICP **Important:** Mission Control can only refill itself by minting new cycles with ICP. #### d. When no top-up is possible If Mission Control doesn't have enough cycles or ICP to perform a refill, the top-up fails. --- ### Notifications After each successful top-up, developers who have opted-in will receive an email notification. These notifications provide details such as the module that was refilled and the amount of cycles added. In the case of failed attempts (e.g., when Mission Control or a module could not be refilled), a single email notification is sent per day to avoid spamming developers in the event of repeated failures. --- ## Configuration To enable monitoring, go to the [Monitoring Section](https://console.juno.build/monitoring) in the Juno Console. Start the wizard by clicking **Get started** and follow the prompts to: * Create the Mission Control service * Select the modules you want to monitor * Choose a pre-defined strategy or create a custom one * Enable the feature The wizard guides you through the setup process, making it easy to configure monitoring according to your needs. --- # Source: https://juno.build/docs/examples/functions/typescript/mutating-docs.md # Source: https://juno.build/docs/examples/functions/rust/mutating-docs.md # Mutating Documents with Rust Hooks This example demonstrates how to use **hooks in Rust** to modify documents automatically when they're created or updated in your Juno **Satellite**. Hooks let you react to events like document creation, deletion, or asset uploads — and run custom backend logic in response. You can browse the source code here: [github.com/junobuild/examples/tree/main/functions/rust/hooks](https://github.com/junobuild/examples/tree/main/functions/rust/hooks) --- ## Folder Structure ``` rust/hooks/├── src/│ ├── satellite/ # Rust Satellite serverless function│ │ ├── src/│ │ │ └── lib.rs # Main Rust logic for Satellite│ │ ├── satellite.did # Candid interface definition│ │ └── Cargo.toml # Rust package config│ ├── declarations/ # TypeScript declarations for Satellite│ ├── admin.ts # Frontend admin logic│ ├── doc.ts # Frontend doc logic│ ├── main.ts # Frontend entry point│ ├── storage.ts # Frontend storage logic│ └── style.css # Frontend styles├── juno.config.ts # Juno Satellite configuration├── package.json # Frontend dependencies└── ... ``` --- ## Key Features * **Serverless Hooks in Rust**: Demonstrates how to react to data and asset operations using hooks in Rust serverless functions. * **Multiple Hook Types**: Includes hooks for document set, set-many, delete, and asset upload operations. * **Serverless Integration**: Runs as a Satellite function and integrates with Juno's datastore and authentication system. * **Minimal UI for Testing**: A simple frontend is included to test and demonstrate the hook logic in action. --- ## Main Backend Components * **src/satellite/src/lib.rs**: The core Rust logic for the Satellite serverless function. Implements hooks for various operations (set, set-many, delete, upload). * **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function. --- ## Example: Mutating Documents Here’s the actual Rust logic from `lib.rs`: ``` use ic_cdk::print;use junobuild_macros::{on_delete_doc, on_set_doc, on_set_many_docs, on_upload_asset};use junobuild_satellite::{ include_satellite, set_doc_store, OnDeleteDocContext, OnSetDocContext, OnSetManyDocsContext, OnUploadAssetContext, SetDoc,};use junobuild_utils::{decode_doc_data, encode_doc_data};use junobuild_utils::{DocDataBigInt, DocDataPrincipal};use serde::{Deserialize, Serialize};/// Example struct used to demonstrate decode/edit/store flow.#[derive(Serialize, Deserialize)]struct Person { yolo: bool, hello: String, principal: DocDataPrincipal, value: DocDataBigInt,}// Hook that runs when a document is set in the "demo" collection#[on_set_doc(collections = ["demo"])]async fn on_set_doc(context: OnSetDocContext) -> Result<(), String> { // Decode the document into our Person struct let mut data: Person = decode_doc_data(&context.data.data.after.data)?; // Log some values for debugging print(format!("[on_set_doc] Caller: {}", context.caller.to_text())); print(format!("[on_set_doc] Collection: {}", context.data.collection)); print(format!("[on_set_doc] Data: {} {}", data.principal.value, data.value.value)); // Modify the document before storing it again data.hello = format!("{} checked", data.hello); data.yolo = false; // Encode and re-store the updated document let encode_data = encode_doc_data(&data)?; let doc: SetDoc = SetDoc { data: encode_data, description: context.data.data.after.description, version: context.data.data.after.version, }; set_doc_store( context.caller, context.data.collection, context.data.key, doc, )?; Ok(())}include_satellite!(); ``` **Explanation:** * Defines a `Person` struct with fields for demo purposes. * Uses the `#[on_set_doc]` macro to run logic whenever a document is set in the `demo` collection. Updates the document and saves it back. * `include_satellite!();` brings in the necessary boilerplate for the Juno Satellite runtime. --- ## How to Run 1. **Clone the repo**: ``` git clone https://github.com/junobuild/examplescd rust/hooks ``` 2. **Install dependencies**: ``` npm install ``` 3. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 4. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 5. **Create required collections**: * `demo` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 6. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` 7. **Build the serverless functions** (in a separate terminal): ``` juno functions build ``` The emulator will automatically upgrade your Satellite and live reload the changes. --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.ts` with the production Satellite ID. * Build and deploy the frontend: ``` npm run buildjuno hosting deploy ``` * Build and upgrade the serverless functions: ``` juno functions buildjuno functions upgrade ``` --- ## Notes * This example focuses on the Rust serverless function. The frontend is intentionally minimal and included only for demonstration. * Use this project as a starting point for writing custom backend logic in Rust using Juno hooks. --- ## Real-World Example Want to see how assertions and serverless logic are used in a live project? Check out [proposals.network](https://proposals.network), an open-source app built with Juno: * GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network) * Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs) This app uses: * `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets * Shared helper modules like `assert`, `delete`, and `types` to keep logic organized * A real-world pattern of chaining asset/document deletions with assertions It’s a great reference for more advanced setups and multi-collection coordination. --- ## References * [Serverless Functions Guide](/docs/guides/rust.md) * [Functions Development](/docs/build/functions.md) * [Rust SDK Reference](/docs/reference/functions/rust/sdk.md) * [Rust Utils Reference](/docs/reference/functions/rust/utils.md) * [Run Local Development](/docs/guides/local-development.md) * [CLI Reference](/docs/reference/cli.md) * [Configuration Reference](/docs/reference/configuration.md) * [Datastore Collections](/docs/build/datastore/collections.md) --- ## Crate Docs These crates are used to build and extend serverless functions in Rust with Juno: * [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration. * [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions. * [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling. * [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console. * [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno. --- # Source: https://juno.build/docs/guides/nextjs.md # Source: https://juno.build/docs/examples/frontend/nextjs.md # Next.js Example This project is a note-taking app template built with **Next.js**, **TypeScript**, and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template nextjs-example ``` Source: [github.com/junobuild/create-juno/templates/nextjs-example](https://github.com/junobuild/create-juno/tree/main/templates/nextjs-example) --- ## Folder Structure ``` nextjs-example/├── public/ # Static assets├── src/│ ├── app/ # Next.js app directory (routing, layout, etc.)│ ├── components/ # React UI components (auth, table, modal, banner, etc.)│ ├── types/ # TypeScript types (e.g., note.ts)├── juno.config.mjs # Juno Satellite configuration├── package.json # Project dependencies and scripts├── next.config.mjs # Next.js configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **src/app/**: Next.js app directory, handles routing and layout. * **components/**: Contains UI and logic for authentication, notes table, modal, banner, etc. * **types/note.ts**: TypeScript interface for notes. --- ## Data Structure * **NoteData** (`src/types/note.ts`): ``` export interface NoteData { text: string; url?: string;}export type Note = Doc; ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.mjs` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * `juno.config.mjs`: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * `next.config.mjs`: Uses the `withJuno` plugin to load environment variables and inject config automatically at build time. See the [Next.js Plugin reference](/docs/reference/plugins.md#nextjs-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.mjs` with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in TypeScript and React function components. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/app/page.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/app/page.tsx) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/components/auth.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/auth.tsx) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/components/login.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/login.tsx) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/components/logout.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/logout.tsx) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/components/table.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/table.tsx) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/components/modal.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/modal.tsx) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/components/delete.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/delete.tsx) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/components/modal.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/modal.tsx) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/components/delete.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/nextjs-example/src/components/delete.tsx) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/reference/functions/typescript/node.md # Node.js The TypeScript runtime used in Juno does not provide full Node.js support. Polyfills are added iteratively to keep the environment stable and predictable. If you require a specific Node.js feature or are blocked by a missing polyfill, please reach out or open an issue. Features are prioritized based on usage and compatibility. --- ## Globals Some global functions are supported but come with important limitations or added details. ### Math.random Generates a pseudo-random number between 0 (inclusive) and 1 (exclusive) is supported. However, the generator is seeded once after upgrade of the Satellite. Use it with caution. **Caution:** Randomness is unsuitable for use cases requiring unpredictable results, like lotteries. ``` const value = Math.random(); ``` --- ### Console Logging is fully supported. Objects are stringified and logs are routed to the IC-CDK `print()` function, making them visible in your Satellite logs including inside the Juno Console UI in development or production. ``` console.log("Hello from the Satellite");console.info("Hello", { type: "info", msg: "Something happened" }); ``` --- # Source: https://juno.build/docs/guides/nodejs.md # Use Juno in a NodeJS context This guide explains how to use Juno from a client running in a non-interactive environment (e.g. NodeJS, scripts, or CI). **Tip:** You can find examples of NodeJS usage in the [example](https://github.com/junobuild/examples/tree/main/node) repository. --- ## Usage The simplest and recommended way to interact with your Juno project is by using the [juno run](/docs/reference/cli.md#run) command provided by the CLI. If you haven't installed it yet, run: * npm * yarn * pnpm ``` npm i -g @junobuild/cli ``` ``` yarn global add @junobuild/cli ``` ``` pnpm add -g @junobuild/cli ``` With `juno run`, you can write custom scripts that automatically inherit your environment (`mode`, `profile`, etc.) and [configuration](/docs/reference/configuration.md). A script — written in JavaScript or TypeScript — must export a single `onRun` produced by `defineRun`. For example: my-task.ts ``` import { defineRun } from "@junobuild/config";export const onRun = defineRun(({ mode, profile }) => ({ run: async ({ satelliteId, identity }) => { console.log("Running task with:", { mode, profile, satelliteId: satelliteId.toText(), whoami: identity.getPrincipal().toText() }); }})); ``` Run it with: ``` juno run --src ./my-task.ts ``` --- ## Example Suppose you want to fetch a document and export it to a file: ``` import { getDoc } from "@junobuild/core";import { defineRun } from "@junobuild/config";import { jsonReplacer } from "@dfinity/utils";import { writeFile } from "node:fs/promises";export const onRun = defineRun(({ mode }) => ({ run: async (context) => { const key = mode === "staging" ? "123" : "456"; const doc = await getDoc({ collection: "demo", key, satellite: context }); await writeFile("./mydoc.json", JSON.stringify(doc, jsonReplacer, 2)); }})); ``` This script retrieves a document using `getDoc`, selects the document ID based on the current `mode` (for example staging or production), and writes the result to `mydoc.json`, using `jsonReplacer` to handle types not supported by JSON such as `BigInt`. --- # Source: https://juno.build/docs/build/authentication/passkeys.md # Passkeys Passkeys let your users authenticate without passwords - using their device's built-in security features such as Face ID, Touch ID, or device unlock. They are built on WebAuthn, providing strong cryptographic security while offering a frictionless, Web2-like user experience. When users sign in with a passkey, their private key never leaves the device. Your Satellite uses only a cryptographic signature to confirm their identity, ensuring authentication is secure and privacy-preserving by default. --- ## How It Works 1. When a user signs up, your project creates a passkey on their device that's tied to your domain. 2. The passkey is stored securely by the device or its manager (e.g. iCloud Keychain, Google Password Manager). 3. On sign-in, the user proves ownership of the passkey by signing twice with their device's authenticator. 4. The identity is verified on the frontend through these signatures, and the resulting public key (the user's identity) is stored in your Satellite. 5. Whenever the user interacts with your app, the Satellite checks that the caller's public key matches the stored one, ensuring the request comes from the legitimate user. **Note:** Passkeys are **domain-scoped**: a passkey created on `hello.com` will work on its subdomains (like `www.hello.com`), but not on different domains (like `world.com`). You can change this behavior during setup if you want to use a higher-level domain as the passkey origin, but not a completely different one. --- ## Sign-up With Passkeys, your users need to sign up to create an identity that grants them access to your application. During this process, the user will be asked to use their authenticator twice: once to generate the passkey, and once more to sign their new identity which is then used to interact securely with your satellite. ``` import { signUp } from "@junobuild/core";await signUp({ webauthn: {}}); ``` **Note:** Returning users don't need to go through sign-up again. They can simply use ([sign-in](#passkeys-1)) with their existing passkey to authenticate. ### Options Passkey sign-up can be customized with a handful of options. These let you control how long a session lasts, how the passkey is displayed to the user, and whether you want to track progress in your own UI. | Option | Type | Default | Description | | --- | --- | --- | --- | | `maxTimeToLiveInMilliseconds` | `number` | **4 hours** | Maximum lifetime of the user's session in **milliseconds**. Once expired, the session cannot be extended. | | `onProgress` | `(progress) => void` | | Callback fired at each step of the sign-up flow (e.g., creating credential, validating, signing). Useful if you want to show progress indicators in your UI. | | `passkey` | `CreatePasskeyOptions` | | Options for how the passkey should be created. | The `passkey` option accepts the following fields: | Option | Type | Default | Description | | --- | --- | --- | --- | | `appId.id` | `string` | Current URL `hostname` | Domain your passkeys are tied to (e.g., `example.com` or `login.example.com`). Subdomains are supported. | | `user.displayName` | `string` | `document.title` | Friendly name for the account (e.g., `"Maria Sanchez"`). Helps the user recognize which passkey belongs to them. | | `user.name` | `string` | `displayName` | User-recognizable account identifier (e.g., email, username, or phone number). Distinguishes between accounts. | Example with options: ``` import { signUp } from "@junobuild/core";await signUp({ webauthn: { options: { maxTimeToLiveInMilliseconds: 1000 * 60 * 60, // 1 hour onProgress: ({ step, state }) => { console.log("Step:", step, "State:", state); }, passkey: { displayName: "My Cool App" // or user input } } }}); ``` **Tip:** It's common to let the user choose a nickname during sign-up. This nickname can be passed as the `displayName` in the `passkey` option so the passkey is easy to recognize the next time they sign in (e.g. in iCloud Keychain or Google Password Manager). --- ## Sign-in Returning users sign in using the digital key previously created on their device — for example in the browser, iCloud Keychain, Google Password Manager, etc. The user will be asked to use their authenticator to prove possession of the passkey and re-establish a valid session with your satellite. ``` import { signIn } from "@junobuild/core";await signIn({ webauthn: {}}); ``` **Note:** New users must first go through ([sign-up](#passkeys)) to create a passkey before they can sign in. ### Options Passkey sign-in can also be customized with options similar to sign-up. These let you control how long a session lasts and whether you want to track progress in your own UI. | Option | Type | Default | Description | | --- | --- | --- | --- | | `maxTimeToLiveInMilliseconds` | `number` | **4 hours** | Maximum lifetime of the user's session in **milliseconds**. Once expired, the session cannot be extended. | | `onProgress` | `(progress) => void` | | Callback fired at each step of the sign-up flow (e.g., fetching credential, validating, signing). Useful to customize your UI. | Example with options: ``` import { signIn } from "@junobuild/core";await signIn({ webauthn: { options: { maxTimeToLiveInMilliseconds: 1000 * 60 * 60, // 1 hour onProgress: ({ step, state }) => { console.log("Step:", step, "State:", state); } } }}); ``` --- ## Context In addition to the options above, some settings apply to both sign-up and sign-in flows themselves. | Option | Type | Default | Description | | --- | --- | --- | --- | | `windowGuard` | `boolean` | `true` | Prevents the user from closing the current window/tab while the flow is in progress. Disabling it is discouraged. | --- ## Checking Availability Not every browser or device supports Passkeys. You can check availability before showing a sign-up or sign-in button with: ``` import { isWebAuthnAvailable } from "@junobuild/core";if (await isWebAuthnAvailable()) { // Show Passkey sign-up option} ``` --- ## Recommendations * Passkeys work best for users who expect a simple, device-native login experience. * Always check for WebAuthn support before showing a Passkey option. * Combine Passkeys with other providers (like [Google](/docs/build/authentication/google.md) or [Internet Identity](/docs/build/authentication/internet-identity.md)) to cover both mainstream and decentralized use cases. * Avoid changing your app's domain setup after users have registered, as identities are tied to the original domain scope. --- # Source: https://juno.build/docs/reference/plugins.md # Plugins Juno provides various plugins to simplify your development workflow. Each plugin automatically loads values from your `juno.config` file into your build environment, so you can call `initSatellite()` and `initOrbiter()` without extra config. --- ## Next.js Plugin Use this plugin to load Juno configuration into your Next.js build with zero manual setup. ### Installation Add it to your dev dependencies with: * npm * yarn * pnpm ``` npm i @junobuild/nextjs-plugin -D ``` ``` yarn add @junobuild/nextjs-plugin -D ``` ``` pnpm add @junobuild/nextjs-plugin -D ``` ### Usage In your Next.js config file — whether it's `next.config.js`, `next.config.ts`, `next.config.mjs` or else — wrap your configuration with `withJuno` to automatically load Juno settings: next.config.js ``` import { withJuno } from "@junobuild/nextjs-plugin";// withJuno wraps your Next.js config and injects values from juno.configexport default withJuno(); ``` ### Options The plugin supports the following options: #### Passing Next.js Options You can pass additional Next.js configuration options using the `nextConfig` field. The plugin will always ensure `output: "export"` is set for static export. next.config.js ``` import { withJuno } from "@junobuild/nextjs-plugin";/** @type {import('next').NextConfig} */const nextConfig = { // Example: add your own Next.js config here i18n: { locales: ["en", "fr"], defaultLocale: "en" }, env: { CUSTOM_VAR: "my-value" }};// Juno will merge this with output: "export" automaticallyexport default withJuno({ nextConfig }); ``` In other words, if you want to include additional Next.js configuration (e.g. `i18n`, `env` etc.), just define them in your `nextConfig` object and pass it to `withJuno`. #### Container You can use the `container` option to: * Provide a custom container URL (e.g. for an emulator running on a specific port), or * Set it to `false` to disable local development behavior entirely. next.config.js ``` import { withJuno } from "@junobuild/nextjs-plugin";export default withJuno({ juno: { container: false } }); ``` ### Environment Variables The plugin injects environment variables derived from your `juno.config` file. You can use these variables in your app, which is especially helpful if you’ve specified a custom prefix other than `NEXT_PUBLIC_`. ``` console.log(process.env.NEXT_PUBLIC_SATELLITE_ID); ``` The following variables are available: | Environment variable | Value | | --- | --- | | NEXT\_PUBLIC\_SATELLITE\_ID | Satellite ID from Juno config (per `mode`) | | NEXT\_PUBLIC\_ORBITER\_ID | `undefined` in development, Orbiter ID from Juno config. | | NEXT\_PUBLIC\_INTERNET\_IDENTITY\_ID | `rdmx6-jaaaa-aaaaa-aaadq-cai` | | NEXT\_PUBLIC\_ICP\_LEDGER\_ID | `ryjl3-tyaaa-aaaaa-aaaba-cai` | | NEXT\_PUBLIC\_ICP\_INDEX\_ID | `qhbym-qaaaa-aaaaa-aaafq-cai` | | NEXT\_PUBLIC\_NNS\_GOVERNANCE\_ID | `rrkah-fqaaa-aaaaa-aaaaq-cai` | | NEXT\_PUBLIC\_CMC\_ID | `rkp4c-7iaaa-aaaaa-aaaca-cai` | | NEXT\_PUBLIC\_REGISTRY\_ID | `rwlgt-iiaaa-aaaaa-aaaaa-cai` | | NEXT\_PUBLIC\_CYCLES\_LEDGER\_ID | `um5iw-rqaaa-aaaaq-qaaba-cai` | | NEXT\_PUBLIC\_CYCLES\_INDEX\_ID | `ul4oc-4iaaa-aaaaq-qaabq-cai` | | NEXT\_PUBLIC\_SNS\_WASM\_ID | `qaa6y-5yaaa-aaaaa-aaafa-cai` | | NEXT\_PUBLIC\_NNS\_DAPP\_ID | `qoctq-giaaa-aaaaa-aaaea-cai` | | NEXT\_PUBLIC\_CONTAINER | Container URL (emulator or custom); `undefined` by default in production | ### More information Discover additional information in the library's [README](https://github.com/junobuild/plugins/tree/main/plugins/nextjs-plugin). --- ## Vite Plugin Use this plugin to integrate Juno configuration into your Vite build process automatically. ### Installation Add it to your dev dependencies with: * npm * yarn * pnpm ``` npm i @junobuild/vite-plugin -D ``` ``` yarn add @junobuild/vite-plugin -D ``` ``` pnpm add @junobuild/vite-plugin -D ``` ### Usage Add the plugin to your Vite configuration — whether you're using TypeScript or JavaScript — to automatically load Juno settings: vite.config.js ``` import juno from "@junobuild/vite-plugin";export default defineConfig({ // Automatically injects values from juno.config for the build plugins: [juno()]}); ``` ### Options You can use the `container` option to: * Provide a custom container URL (e.g. for an emulator running on a specific port), or * Set it to `false` to disable local development behavior entirely. vite.config.js ``` import juno from "@junobuild/vite-plugin";export default defineConfig({ plugins: [ juno({ container: false }) ]}); ``` ### Environment Variables The plugin injects environment variables derived from your `juno.config` file. You can use these variables in your app, which is especially helpful if you’ve specified a prefix other than the default, such as `VITE_` or `PUBLIC_`. ``` console.log(process.env.VITE_SATELLITE_ID); ``` The following variables are available: | Environment variable | Value | | --- | --- | | VITE\_SATELLITE\_ID | Satellite ID from Juno config (per `mode`) | | VITE\_ORBITER\_ID | `undefined` in development, Orbiter ID from Juno config. | | VITE\_INTERNET\_IDENTITY\_ID | `rdmx6-jaaaa-aaaaa-aaadq-cai` | | VITE\_ICP\_LEDGER\_ID | `ryjl3-tyaaa-aaaaa-aaaba-cai` | | VITE\_ICP\_INDEX\_ID | `qhbym-qaaaa-aaaaa-aaafq-cai` | | VITE\_NNS\_GOVERNANCE\_ID | `rrkah-fqaaa-aaaaa-aaaaq-cai` | | VITE\_CMC\_ID | `rkp4c-7iaaa-aaaaa-aaaca-cai` | | VITE\_REGISTRY\_ID | `rwlgt-iiaaa-aaaaa-aaaaa-cai` | | VITE\_CYCLES\_LEDGER\_ID | `um5iw-rqaaa-aaaaq-qaaba-cai` | | VITE\_CYCLES\_INDEX\_ID | `ul4oc-4iaaa-aaaaq-qaabq-cai` | | VITE\_SNS\_WASM\_ID | `qaa6y-5yaaa-aaaaa-aaafa-cai` | | VITE\_NNS\_DAPP\_ID | `qoctq-giaaa-aaaaa-aaaea-cai` | | VITE\_PUBLIC\_CONTAINER | Container URL (emulator or custom); `undefined` by default in production | ### More information Discover additional options in the library's [README](https://github.com/junobuild/plugins/tree/main/plugins/vite-plugin). --- # Source: https://juno.build/docs/pricing.md # Pricing Juno has a simple starting point: * ✅ Free to get started: new developers receive credits to create a container for their first project, with initial resources included, ready to use. * 💰 Pay as you grow: additional modules (for projects, monitoring or analytics) cost 3 T Cycles each to create. * 📦 Operating costs: ongoing costs for storage, compute, and deployments are paid with cycles. From there, you can dive into the details below to estimate storage, deployment, and data costs more precisely. --- ## Operating costs As the owner of your Mission Control, Satellites and Orbiters, you are responsible for their operating costs. To ensure that your infrastructure usage is covered, you must maintain a minimum balance of [cycles](/docs/terminology.md#cycles). You can top up your cycle balance in the Juno [console](https://console.juno.build/) through one of the following methods: * Purchasing cycles with Stripe, thanks to our friends at [cycle.express](https://cycle.express). * Using cycles from your [wallet](/docs/miscellaneous/wallet.md). * Transferring cycles between modules, such as moving cycles from one Satellite to another. --- ## Transaction costs New developers who join Juno are granted credits to create an initial [Satellite](/docs/terminology.md#satellite). To create additional Satellites, a fee of 3 T Cycles is necessary, along with the infrastructure costs for setting up the container. Similarly, enabling analytics by creating an [Orbiter](/docs/terminology.md#orbiter) or monitoring with a [Mission Control](/docs/terminology.md#mission-control) entails a fee of 3 T Cycles. Each module is provisioned with approximately 1.5 T Cycles in usable resources. **Note:** * For backwards compatibility, modules can still be created using Mission Control (deprecated). The transaction cost for this approach is 1.5 ICP. * Additional transaction fees may be introduced in the future, and pricing and models are subject to change. --- ## Estimating Costs Below are a few examples of costs provided for explanatory purposes only. Actual costs may vary depending on network conditions and usage patterns. **Tip:** You can use the [Pricing Calculator](https://internetcomputer.org/docs/current/developer-docs/cost-estimations-and-examples) to get a better rough estimate of how much your project might cost. ### Storage The estimated annual cost of storing 1 gigabyte of data on the Internet Computer is $5. To calculate the estimated monthly cost for 1 gigabyte of storage, you can refer to the table provided on the Internet Computer [website](https://internetcomputer.org/docs/current/developer-docs/gas-cost). | Transaction | 13-node Application Subnets | 34-node Application Subnets | | --- | --- | --- | | GB Storage Per Second | $0.000000169749 | $0.000000443960 | | Derived to a 30-day month | $0.439 | $1.149 | | Derived to a 12-month year | $5.268 | $13.788 | ### Deployment Based on our experimentation, deploying an entire website, such as the website [http://juno.build](http://juno.build), which consists of approximately 900 files (including compressed versions of the files) and is 40 MB in size, is estimated to cost around 0.114 T Cycles, which converts to 0.0105 ICP ($0.15). It's important to note that subsequent deployments of your project can have significantly lower costs if the build consistency of your application is maintained. Juno only uploads new files to your Satellites, which helps reduce costs compared to initial deployments. ### Data Querying data on the Internet Computer is currently free, so there are no additional costs to expect when reading data. In terms of persisting data, based on our experience, storing 100 instances of a JSON sample data with approximately 90 fields, totaling around 900 bytes, costs approximately 0.0005 TCycles ($0.000675). This means that the cost for a single transaction of this nature would be approximately 0.000005 TCycles or 0.0000017 ICP ($0.00000675). **Note:** Pricing information was last reviewed on Jan. 7, 2026. Figures are estimates and may change as the Internet Computer evolves. --- # Source: https://juno.build/docs/miscellaneous/provisioning-options.md # Provisioning Options The creation wizard for Satellites and Orbiters includes advanced provisioning options for developers who need more control. --- ## Hosting Memory When you initialize a satellite, you must decide how the frontend will be kept in memory and served on the web. In the Console this is presented as _"What are you building? Website or Application"_. If you pick Website, the hosting will be provisioned on heap memory. If you pick Application, it will be on stable memory. Heap provides the fastest response. It is a good choice when you want to deliver content as quickly as possible to users, and it also benefits SEO, since speed matters. For this reason, it is the default for websites. Stable is slightly more expensive and slower on average. Unlike heap, each access requires data to be deserialized. This process is fast but still has an impact. The advantage of stable comes during upgrades: assets do not need to be serialized and deserialized again, which means you are not limited to 1 GB of assets. For this reason, stable is the default for applications with rich features, such as single-page applications. Our benchmarks showed that heap generally delivered more consistent responses with fewer slow spikes. Stable performed similarly on average but tended to be spikier under load. For larger assets, heap was typically faster and more reliable at higher percentiles, though it could show a small startup penalty or the occasional outlier. Lighthouse measurements indicated that stable added roughly 0.5 seconds to CFP compared to heap for a small website. Ultimately, there are no strict rules. You can use heap for an application or stable for a website. You can also switch from one to the other in Hosting > Settings in the Console, with the prerequisite that no files are being served at the time of the switch. **Info:** For more background on memory behavior and limits, see the [Memory](/docs/miscellaneous/memory.md) documentation. --- ## Selecting a Subnet If you want more control over where your module is provisioned, you can select a [subnet](/docs/terminology.md#subnet) during the creation process. Below is a list of available subnets with relevant metadata to help you choose the most appropriate one: **Note:** Satellites and Orbiters running on larger subnets with more nodes will incur higher cycle costs compared to those on the standard 13-node subnets. However, this increased cost comes with the benefit of enhanced security due to the greater size of the subnet. For most applications, we recommend using the default subnets and staying on the same subnet as Juno. | Subnet ID | Type | Canisters (Running/Stopped) | Nodes (Up/Total) | | --- | --- | --- | --- | | 6pbhf-qzpdk-kuqbr-pklfa-5ehhf-jfjps-zsj6q-57nrl-kzhpd-mu7hc-vae | Juno's Subnet | 36101/703 | 13/13 | | pzp6e-ekpqk-3c5x7-2h6so-njoeq-mt45d-h3h6c-q3mxf-vpeq5-fk5o7-yae | Fiduciary | 3564/12 | 34/34 | | bkfrj-6k62g-dycql-7h53p-atvkj-zg4to-gaogh-netha-ptybj-ntsgw-rqe | European | 25096/663 | 13/13 | | brlsh-zidhj-3yy3e-6vqbz-7xnih-xeq2l-as5oc-g32c4-i5pdn-2wwof-oae | | 35432/815 | 13/13 | | o3ow2-2ipam-6fcjo-3j5vt-fzbge-2g7my-5fz2m-p4o2t-dwlc4-gt2q7-5ae | | 57571/170 | 13/13 | | 4ecnw-byqwz-dtgss-ua2mh-pfvs7-c3lct-gtf4e-hnu75-j7eek-iifqm-sqe | | 8684/303 | 13/13 | | opn46-zyspe-hhmyp-4zu6u-7sbrh-dok77-m7dch-im62f-vyimr-a3n2c-4ae | | 40491/835 | 13/13 | | nl6hn-ja4yw-wvmpy-3z2jx-ymc34-pisx3-3cp5z-3oj4a-qzzny-jbsv3-4qe | | 32293/818 | 13/13 | | io67a-2jmkw-zup3h-snbwi-g6a5n-rm5dn-b6png-lvdpl-nqnto-yih6l-gqe | | 2997/2528 | 13/13 | | ejbmu-grnam-gk6ol-6irwa-htwoj-7ihfl-goimw-hlnvh-abms4-47v2e-zqe | | 12068/111 | 13/13 | | gmq5v-hbozq-uui6y-o55wc-ihop3-562wb-3qspg-nnijg-npqp5-he3cj-3ae | | 34558/256 | 13/13 | | pjljw-kztyl-46ud4-ofrj6-nzkhm-3n4nt-wi3jt-ypmav-ijqkt-gjf66-uae | | 32743/243 | 12/13 | | 4zbus-z2bmt-ilreg-xakz4-6tyre-hsqj4-slb4g-zjwqo-snjcc-iqphi-3qe | | 59568/87 | 13/13 | | 5kdm2-62fc6-fwnja-hutkz-ycsnm-4z33i-woh43-4cenu-ev7mi-gii6t-4ae | | 13234/154 | 13/13 | | e66qm-3cydn-nkf4i-ml4rb-4ro6o-srm5s-x5hwq-hnprz-3meqp-s7vks-5qe | | 35861/769 | 13/13 | | qdvhd-os4o2-zzrdw-xrcv4-gljou-eztdp-bj326-e6jgr-tkhuc-ql6v2-yqe | | 53577/125 | 13/13 | | snjp4-xlbw4-mnbog-ddwy6-6ckfd-2w5a2-eipqo-7l436-pxqkh-l6fuv-vae | | 4277/1511 | 13/13 | | shefu-t3kr5-t5q3w-mqmdq-jabyv-vyvtf-cyyey-3kmo4-toyln-emubw-4qe | | 3004/2624 | 13/13 | | csyj4-zmann-ys6ge-3kzi6-onexi-obayx-2fvak-zersm-euci4-6pslt-lae | | 3682/1812 | 13/13 | | yinp6-35cfo-wgcd2-oc4ty-2kqpf-t4dul-rfk33-fsq3r-mfmua-m2ngh-jqe | | 8457/582 | 13/13 | | w4asl-4nmyj-qnr7c-6cqq4-tkwmt-o26di-iupkq-vx4kt-asbrx-jzuxh-4ae | | 3151/2468 | 12/13 | | c4isl-65rwf-emhk5-5ta5m-ngl73-rgrl3-tcc56-2hkja-4erqd-iivmy-7ae | | 1700/4011 | 13/13 | | mpubz-g52jc-grhjo-5oze5-qcj74-sex34-omprz-ivnsm-qvvhr-rfzpv-vae | | 55938/327 | 12/13 | | fuqsr-in2lc-zbcjj-ydmcw-pzq7h-4xm2z-pto4i-dcyee-5z4rz-x63ji-nae | | 22380/117 | 13/13 | | cv73p-6v7zi-u67oy-7jc3h-qspsz-g5lrj-4fn7k-xrax3-thek2-sl46v-jae | | 51889/339 | 13/13 | | pae4o-o6dxf-xki7q-ezclx-znyd6-fnk6w-vkv5z-5lfwh-xym2i-otrrw-fqe | | 5134/630 | 13/13 | | qxesv-zoxpm-vc64m-zxguk-5sj74-35vrb-tbgwg-pcird-5gr26-62oxl-cae | | 2531/3146 | 13/13 | | 4utr6-xo2fz-v7fsb-t3wsg-k7sfl-cj2ba-ghdnd-kcrfo-xavdb-ebean-mqe | | 2756/3071 | 13/13 | | lspz2-jx4pu-k3e7p-znm7j-q4yum-ork6e-6w4q6-pijwq-znehu-4jabe-kqe | | 40004/944 | 13/13 | | jtdsg-3h6gi-hs7o5-z2soi-43w3z-soyl3-ajnp3-ekni5-sw553-5kw67-nqe | | 27813/206 | 13/13 | --- # Source: https://juno.build/docs/guides/github-actions/publish-functions.md # Build and Publish Serverless Functions This section explains how to automate the build and publication of your serverless functions using GitHub Actions. The process works for functions written in TypeScript or Rust and helps integrate function deployment into your development workflow. --- ## Configuration To configure an action to build and publish serverless functions, follow these steps: 1. Create or edit `publish.yml` in `.github/workflows/`. 2. Paste the following code into the file: * npm * yarn * pnpm .github/workflows/publish.yml ``` name: Publish Serverless Functionson: workflow_dispatch: push: branches: [main]jobs: publish: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Install Dependencies run: npm ci - name: Build uses: junobuild/juno-action@full with: args: functions build - name: Publish uses: junobuild/juno-action@full with: args: functions publish env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/publish.yml ``` name: Publish Serverless Functionson: workflow_dispatch: push: branches: [main]jobs: publish: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Enable Corepack run: corepack enable - name: Activate Yarn run: corepack prepare yarn@1.x --activate - name: Install Dependencies run: yarn install --frozen-lockfile - name: Build uses: junobuild/juno-action@full with: args: functions build - name: Publish uses: junobuild/juno-action@full with: args: functions publish env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/publish.yml ``` name: Publish Serverless Functionson: workflow_dispatch: push: branches: [main]jobs: publish: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - uses: pnpm/action-setup@v4 with: version: 10 - name: Install Dependencies run: pnpm i --frozen-lockfile - name: Build uses: junobuild/juno-action@full with: args: functions build - name: Publish uses: junobuild/juno-action@full with: args: functions publish env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` This action will build and publish your serverless function bundle. If your access key is an **editor**, the changes will be automatically deployed to your Satellite's CDN. If your key is only a **submitter**, the release will be proposed as a pending change for manual approval. To avoid errors in submit-only workflows, you can explicitly use the `--no-apply` flag to skip auto-application. ``` - name: Publish uses: junobuild/juno-action@full with: args: functions publish --no-apply env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` --- ## Optimization & Best Practices Below are key considerations to ensure efficient and cost-effective publication of your functions. ### Triggering on Release You can adjust the trigger to publish your serverless function only on releases, which helps reduce unnecessary CI runs and deployments. ``` on: release: types: [released] ``` This ensures that your function bundle is built and published only when a GitHub release is published. --- # Source: https://juno.build/docs/examples/frontend/react-javascript.md # React JavaScript Example This project is a note-taking app template built with **React**, **JavaScript**, and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template react-example ``` Source: [github.com/junobuild/create-juno/templates/react-example](https://github.com/junobuild/create-juno/tree/main/templates/react-example) --- ## Folder Structure ``` react-example/├── public/ # Static assets├── src/│ ├── components/ # React UI components (Auth, Table, Modal, Banner, etc.)│ ├── App.jsx # Main app component│ ├── main.jsx # React entry point│ └── index.css # Tailwind CSS styles├── juno.config.mjs # Juno Satellite configuration├── package.json # Project dependencies and scripts├── vite.config.js # Vite build configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **App.jsx**: Initializes Juno Satellite, renders the main layout, and wraps content in authentication. * **Banner.jsx**: Shows a warning if the Satellite ID is missing in local dev. * **Auth.jsx**: Provides authentication context and login/logout UI. * **Table.jsx**: Displays the list of notes from the Datastore. * **Modal.jsx**: Handles note creation and editing. * **Delete.jsx**: Handles note deletion. * **Footer.jsx, Background.jsx, Button.jsx, etc.**: UI and utility components. --- ## Data Structure * **Note** (used in Table.jsx): ``` // Example note object{ key: string, data: { text: string, url?: string }} ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.mjs` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * **juno.config.mjs**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.js**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.mjs` with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in JavaScript and React function components. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/App.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/App.jsx) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/components/Auth.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Auth.jsx) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/components/Login.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Login.jsx) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/components/Logout.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Logout.jsx) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/components/Table.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Table.jsx) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/components/Modal.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Modal.jsx) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/components/Delete.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Delete.jsx) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/components/Modal.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Modal.jsx) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/components/Delete.jsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-example/src/components/Delete.jsx) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/examples/frontend/react-typescript.md # React TypeScript Example This project is a note-taking app template built with **React**, **TypeScript**, and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template react-ts-example ``` Source: [github.com/junobuild/create-juno/templates/react-ts-example](https://github.com/junobuild/create-juno/tree/main/templates/react-ts-example) --- ## Folder Structure ``` react-ts-example/├── public/ # Static assets├── src/│ ├── components/ # React UI components (Auth, Table, Modal, Banner, etc.)│ ├── types/ # TypeScript types (e.g., note.ts)│ ├── App.tsx # Main app component│ ├── main.tsx # React entry point│ └── index.css # Tailwind CSS styles├── juno.config.ts # Juno Satellite configuration├── package.json # Project dependencies and scripts├── vite.config.ts # Vite build configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **App.tsx**: Initializes Juno Satellite, renders the main layout, and wraps content in authentication. * **Banner.tsx**: Shows a warning if the Satellite ID is missing in local dev. * **Auth.tsx**: Provides authentication context and login/logout UI. * **Table.tsx**: Displays the list of notes from the Datastore. * **Modal.tsx**: Handles note creation and editing. * **Delete.tsx**: Handles note deletion. * **Footer.tsx, Background.tsx, Button.tsx, etc.**: UI and utility components. --- ## Data Types * **NoteData** (`src/types/note.ts`): ``` export interface NoteData { text: string; url?: string;}export type Note = Doc; ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in JavaScript and React function components. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/App.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/App.tsx) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/components/Auth.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Auth.tsx) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/components/Login.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Login.tsx) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/components/Logout.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Logout.tsx) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/components/Table.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Table.tsx) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/components/Modal.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Modal.tsx) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/components/Delete.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Delete.tsx) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/components/Modal.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Modal.tsx) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/components/Delete.tsx`](https://github.com/junobuild/create-juno/blob/main/templates/react-ts-example/src/components/Delete.tsx) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/guides/react.md # React Explore how to create a Juno project developed with React. [## 📄️ Build Learn how to integrate Juno with React. Follow our quickstart guide to set up your development environment, configure your project, and start building with Juno.](/docs/guides/react/build.md) [## 📄️ Deploy Learn how to deploy your React project to Juno. Follow the deployment guide to configure static exports, set up your Satellite, and publish your site to production.](/docs/guides/react/deploy.md) --- # Source: https://juno.build/docs/reference/functions/rust.md # Source: https://juno.build/docs/guides/rust.md # Source: https://juno.build/docs/examples/functions/rust.md # Source: https://juno.build/docs/build/functions/development/rust.md # Rust This page covers advanced options for writing serverless functions in Rust. --- ## Including the Satellite After defining your Functions, at the very end of your `lib.rs` module, include the Satellite to ensure that your custom logic and the default features or Juno are properly registered and executable within the Juno ecosystem. **Important:** This is crucial for compatibility with the Juno Console and CLI, as it expects the Satellite to expose the necessary functionality for monitoring, deployment, and interaction. Without this macro, certain features in the Console may not function correctly. ``` include_satellite!(); ``` --- ## Feature Selection When you run `juno functions eject`, all the available hooks and assertions are scaffolded in your `lib.rs` module. However, if you don’t have to implement all of them for example to improve readability or reduce unnecessary logic, you can selectively enable only the features you need. To do this, disable the default features in your `Cargo.toml` and explicitly specify only the ones you want to use. For example, if you only need `on_set_doc` and `assert_set_doc`, configure your `Cargo.toml` like this: ``` [dependencies]junobuild-satellite = { version = "0.0.21", default-features = false, features = ["on_set_doc", "assert_set_doc"] } ``` With this setup, only `on_set_doc` and `assert_set_doc` must be implemented with custom logic, while other hooks and assertions will not be included in your Satellite. --- ## Maintenance After deployment, keeping your Satellite functional and optimized requires ongoing monitoring and updates. Staying up to date is also a key factor, as we may introduce new features that need to be integrated into your Satellite to ensure full functionality within the Juno Console. Since your project includes all Satellite features using `include_satellite!();`, it's essential to stay in sync with Juno’s updates to maintain compatibility. **Caution:** Always upgrade iteratively and avoid skipping version numbers. While we strive to minimize breaking changes, it's crucial to upgrade through each released version sequentially. For example, if you're on **v0.0.23** and the latest release is **v0.0.26**, first upgrade to **v0.0.24**, then **v0.0.25**, and finally **v0.0.26**. Skipping versions could lead to unexpected issues. ### Updating Your Satellite To upgrade your Satellite, bump the dependencies in your `Cargo.toml` file located in `/src/satellite/`. The key dependencies to check and update are: * `junobuild-satellite` * `junobuild-storage` * `junobuild-macros` * `ic_cdk` * `candid` If other crates in your project depend on these, they should also be upgraded accordingly. The recommended versions for each release can be found in the [changelog](/changelog) or [release notes on GitHub](https://github.com/junobuild/juno/releases). If you need assistance, feel free to reach out through the available support channels. --- ## Versioning Every Satellite that runs your serverless functions includes a version number, defined in the `Cargo.toml` file of your project: ``` [package]name = "satellite"version = "0.1.0" ``` This version is embedded into the compiled Wasm binary and displayed in the Juno Console. It helps you: * Track which version of your serverless logic is currently deployed. * Debug more effectively by matching behavior in the Console with specific code versions. * Move independently of Juno updates — you're in full control of your own function versioning. You can use any versioning scheme that suits your development workflow (e.g. `0.1.0`, `1.0.0-beta`, `2025.04.18`...). --- ## Additional Notes WebAssembly (Wasm) binaries serve as the compilation target for the Satellites. While Juno's CLI automatically specifies this target for you, manual execution of certain `cargo` commands necessitates explicitly providing this target. For instance: ``` cargo clippy --target=wasm32-unknown-unknown ``` --- # Source: https://juno.build/docs/reference/emulator/satellite.md # Satellite Unlike Skylab, the image [junobuild/satellite](https://hub.docker.com/r/junobuild/satellite) runs a single Satellite in a headless environment, without the Console UI. It always mounts the same Satellite, using the fixed ID `jx5yt-yyaaa-aaaal-abzbq-cai`. --- ## Configuration To use this image, your configuration must include the `satellite` field in the `emulator` section. Make also sure to set the `runner` type to match your container runtime, and define the static Satellite ID expected by the image. juno.config.ts ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { development: "jx5yt-yyaaa-aaaal-abzbq-cai", production: "" }, source: "dist", predeploy: ["npm run build"] }, emulator: { runner: { type: "docker" }, satellite: {} }}); ``` For more advanced options like customizing ports, image name, or CI setup, see the [Emulator Configuration](/docs/reference/configuration.md#emulator-configuration) section. --- # Source: https://juno.build/docs/reference/functions/typescript/sdk.md # Source: https://juno.build/docs/reference/functions/rust/sdk.md # SDK The following functions are provided to help you work with document and asset data inside your Satellite. They are part of the tools available when writing serverless functions in Rust and support common tasks such as interacting with the datastore, storage, and custom hook logic. **📦 Crate:** The SDK is provided by the [junobuild-satellite](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/index.html) crate. To use them, add this to your Cargo.toml: ``` [dependencies]junobuild-satellite = "*" ``` You have to follow the pace of the Juno release to ensure compatibility. Refer to the [maintenance guide](/docs/build/functions/development/rust.md#maintenance) for instructions. --- ## Datastore The following functions can be used to manage documents within the Datastore from your serverless functions. --- ### set\_doc\_store Sets a document in a collection’s of the datastore. Use this to insert or update document data. ``` pub fn set_doc_store( caller: UserId, collection: CollectionKey, key: Key, value: SetDoc,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.set_doc_store.html) --- ### get\_doc\_store Retrieves a document from a collection. ``` pub fn get_doc_store( caller: UserId, collection: CollectionKey, key: Key,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.get_doc_store.html) --- ### list\_docs\_store Lists documents in a collection based on filter criteria. ``` pub fn list_docs_store( caller: Principal, collection: CollectionKey, filter: &ListParams,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.list_docs_store.html) --- ### count\_docs\_store Counts documents in a collection based on filter criteria. ``` pub fn count_docs_store( caller: Principal, collection: CollectionKey, filter: &ListParams,) -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.count_docs_store.html) --- ### count\_collection\_docs\_store Counts all documents in a collection. ``` pub fn count_collection_docs_store( collection: &CollectionKey) -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.count_collection_docs_store.html) --- ### delete\_doc\_store Deletes a document from a collection. ``` pub fn delete_doc_store( caller: UserId, collection: CollectionKey, key: Key, value: DelDoc,) -> Result>, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.delete_doc_store.html) --- ### delete\_docs\_store Deletes all documents in a collection. ``` pub fn delete_docs_store( collection: &CollectionKey) -> Result<(), String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.delete_docs_store.html) --- ### delete\_filtered\_docs\_store Deletes documents matching filter criteria. ``` pub fn delete_filtered_docs_store( caller: Principal, collection: CollectionKey, filter: &ListParams,) -> Result>>, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.delete_filtered_docs_store.html) --- ## Storage The following functions can be used to manage assets within the Storage from your serverless functions. --- ### set\_asset\_handler Sets an asset in the store for the identity encoding (no compression applied). ``` pub fn set_asset_handler( key: &AssetKey, content: &Blob, headers: &[HeaderField],) -> Result<(), String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.set_asset_handler.html) --- ### get\_asset\_store Retrieves an asset from a collection. ``` pub fn get_asset_store( caller: Principal, collection: &CollectionKey, full_path: FullPath,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.get_asset_store.html) --- ### list\_assets\_store Lists assets in a collection, excluding their content. ``` pub fn list_assets_store( caller: Principal, collection: &CollectionKey, filters: &ListParams,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.list_assets_store.html) --- ### count\_assets\_store Counts assets in a collection matching the filter criteria. ``` pub fn count_assets_store( caller: Principal, collection: &CollectionKey, filters: &ListParams,) -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.count_assets_store.html) --- ### count\_collection\_assets\_store Counts all assets in a collection. ``` pub fn count_collection_assets_store( collection: &CollectionKey,) -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.count_collection_assets_store.html) --- ### delete\_asset\_store Deletes an asset from a collection. ``` pub fn delete_asset_store( caller: Principal, collection: &CollectionKey, full_path: FullPath,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.delete_asset_store.html) --- ### delete\_assets\_store Deletes all assets in a collection. ``` pub fn delete_assets_store( collection: &CollectionKey,) -> Result<(), String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.delete_assets_store.html) --- ### delete\_filtered\_assets\_store Deletes assets matching filter criteria. ``` pub fn delete_filtered_assets_store( caller: Principal, collection: CollectionKey, filters: &ListParams,) -> Result>, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.delete_filtered_assets_store.html) --- ### set\_asset\_token\_store Set or update an access token for an asset. ``` pub fn set_asset_token_store( caller: Principal, collection: &CollectionKey, full_path: &FullPath, token: &AssetAccessToken,) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.set_asset_token_store.html) --- ### get\_content\_chunks\_store Retrieves content chunks of an asset. Particularly useful when stable memory is used. ``` pub fn get_content_chunks_store( encoding: &AssetEncoding, chunk_index: usize, memory: &Memory,) -> Option ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.get_content_chunks_store.html) --- ## Controllers The following functions allow you to inspect and assert the controllers of your Satellite. --- ### get\_controllers Retrieves all controllers of the Satellite. ``` pub fn get_controllers() -> Controllers ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.get_controllers.html) --- ### get\_admin\_controllers Retrieves only the admin controllers of the Satellite. ``` pub fn get_admin_controllers() -> Controllers ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.get_admin_controllers.html) --- ## Others The SDK also provides various Satellite-specific functions --- ### random Generates a random `i32`. **Caution:** The generator is seeded once after upgrade of the Satellite. This makes it unsuitable for use cases requiring unpredictable randomness, like lotteries. ``` pub fn random() -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-satellite/latest/junobuild_satellite/fn.random.html) --- # Source: https://juno.build/docs/reference/settings.md # Settings This document will help you understand the different settings you can configure for your modules ([Satellites](/docs/terminology.md#satellite), [Mission controls](/docs/terminology.md#mission-control), and [Orbiters](/docs/terminology.md#orbiter)). --- ## Freezing Threshold The Freezing Threshold defines the duration (in seconds) after which a module will be frozen. It acts as a **grace period** before permanent deletion. When a module runs out of cycles, it will be uninstalled, meaning its code and state are deleted. The freezing threshold protects against this by halting the processing of new requests once the cycle balance drops below the threshold, while still allowing read-only replies to existing requests. This grace period gives developers and users time to react. For sensitive applications, it's common to set a relatively long freezing threshold to ensure there’s enough time to notice a low balance and top up the module before removal That’s why [Mission Control](/docs/terminology.md#mission-control) (your wallet) and [Satellites](/docs/terminology.md#satellite) (your projects) are spun up with a default freezing threshold of **one year** (360 days), reflecting their high importance. In contrast, [Analytics](/docs/build/analytics.md) modules are considered less critical and are provisioned with a default threshold of **three months** (90 days). ### In Other Words To remain active and able to respond to state-changing requests—like updating data—a module must maintain a cycles balance that covers the cost of the freezing threshold period. For example, if a module currently has 1 TCycles but needs 5 TCycles to stay alive for the 30-day freezing threshold, it will be considered frozen. If it is topped up to 5.1 TCycles, it becomes active again and can resume processing requests—until that extra 0.1 TCycles is consumed. ### Example of calculation We want to calculate how many cycles are required to keep a module from being frozen, based on the freezing threshold and idle cycle burn rate. Let’s say: * **Freezing Threshold**: 2,592,000 seconds (30 days) * **Idle Cycles Burned per Day**: 0.01 T Cycles (i.e. 10,000,000,000 cycles) To compute the required cycles for the freezing threshold: ``` required_cycles = (idle_cycles_burned_per_day × freezing_threshold_seconds) / 86,400 ``` > 86,400 is the number of seconds in one day Substitute the values: ``` required_cycles = (10,000,000,000 × 2,592,000) / 86,400= 25,920,000,000,000,000 / 86,400= 300,000,000,000 cycles= 0.3 T Cycles ``` Result ✅: With a freezing threshold of 30 days and an idle burn rate of 0.01 T Cycles per day, the module must have a cycles balance greater than 0.3 T Cycles to avoid being frozen and to continue processing update requests. --- ## Reserved Cycles Limit The Reserved Cycles Limit sets the maximum number of cycles a module can reserve. If the reserved cycles exceed this limit, any operation requiring resources, such as compute or memory, will fail. The default value is `5_000_000_000_000n` (5 trillion cycles) ### Example A practical use case could be a scenario where a module is expected to handle a large amount of data storage or perform intensive computations. By setting the Reserved Cycles Limit, developers can control the maximum amount of cycles that can be reserved for the future resource payments. This helps in preventing the module from exceeding its allocated budget and also ensures that it has enough cycles for its operations. --- ## Log Visibility This setting controls who can see the default logs provided by the Internet Computer. It can be set to different levels of visibility, such as `public` or restricted to `controllers`. You can find the logs in the "Functions" section of Juno's administration Console. The default value is `controllers`. **Tip:** On Juno, an administrative access key is a controller. ### Example If you set log visibility to `public`, anyone can view the logs of the module. --- ## Heap Memory Limit This setting defines the maximum amount of `heap` memory a module can use. It helps in controlling the memory usage of the module and prevents issues when upgrading. That is why the default limit for Satellites is set to 1 GB. ### Example If you set the heap memory limit to `2048n`, the module can use up to 2 GiB. Note, however, as mentioned above, that we assume the effective limit to ensure upgrades lies around 1 GiB. --- ## Memory Allocation This setting specifies the amount of memory that is pre-allocated to the module. Pre-allocating memory can help in optimizing the module's performance by ensuring it has a guaranteed amount of memory available from the start. The default value is `0n` - i.e. no particular pre-allocation. ### Example If you set memory allocation to `1_073_741_824n` (1 GiB), the module will have 1 GiB of memory allocated to it from the start. This ensures that the module has sufficient memory pre-allocated for its operations, potentially improving its performance by reducing the need for dynamic memory allocation during execution. --- ## Compute Allocation This setting defines the percentage of compute capacity allocated to the module. It ensures that the module gets a certain share of compute resources. The default value is `0n` - i.e. no particular allocation. ### Example If you set the compute allocation to `50n`, the module will be allocated 50% of the compute capacity. This ensures that the module has a guaranteed share of the compute resources, potentially improving its performance by ensuring it has sufficient processing power for its operations. --- # Source: https://juno.build/docs/setup-the-sdk.md # Setup the SDK To connect your app to a Satellite and use Juno's features — like authentication, data, storage, and serverless functions — you'll need to initialize the SDK. This guide walks you through how to do that, whether you're using a plugin (Next.js, Vite) or setting things up manually. **Info:** If you intend to use Juno solely for **[hosting](/docs/build/hosting.md)** purposes, you may skip the following steps. --- ## TL;DR 1. Call `initSatellite()` in your app code 2. Create a `juno.config` file at the root to define your Satellite 3. Connect code and config — preferably using the `@junobuild/nextjs-plugin` or `@junobuild/vite-plugin` --- ## Initialization 1. Install the Juno SDK: * npm * yarn * pnpm ``` npm i @junobuild/core ``` ``` yarn add @junobuild/core @icp-sdk/core @icp-sdk/auth @dfinity/utils ``` ``` pnpm add @junobuild/core @icp-sdk/core @icp-sdk/auth @dfinity/utils ``` 2. Initialize your Satellite in your web app: ``` import { initSatellite } from "@junobuild/core";await initSatellite(); ``` It is generally recommended to initialize globally the library at the top of your application. --- ## Configuration Juno uses a configuration file to determine which Satellite to connect to. You can scaffold a minimal `juno.config` file using: ``` npx @junobuild/cli init --minimal ``` This creates a `juno.config` file — in TypeScript, JavaScript, or JSON depending on your preferences — at the root of your project. It contains metadata such as the Satellite ID used during SDK initialization. --- ## Connecting Code and Config If you're using **Next.js** or **Vite**, we recommend installing the official plugin. It automatically loads values from your config file and injects them into your build as environment variables. This means you can call `initSatellite()` without passing any parameters, the SDK will read them automatically from `process.env` or `import.meta.env`. * [Next.js Plugin](/docs/reference/plugins.md#nextjs-plugin) next.config.js ``` import { withJuno } from "@junobuild/nextjs-plugin";// withJuno wraps your Next.js config and injects values from juno.configexport default withJuno(); ``` * [Vite Plugin](/docs/reference/plugins.md#vite-plugin) vite.config.js ``` import juno from "@junobuild/vite-plugin";// Automatically injects values from juno.config for the buildexport default defineConfig({ plugins: [juno()]}); ``` **Note:** The templates already include both the config file and the plugin setup. #### Not using a plugin? You can also pass the Satellite ID manually to the SDK, though using the plugins is the preferred approach: ``` import { initSatellite } from "@junobuild/core";await initSatellite({ satelliteId: "your-actual-satellite-id"}); ``` --- # Source: https://juno.build/docs/build/analytics/setup.md # Setup This section covers how to integrate and configure Juno Analytics in your app or website. --- ## Getting Started Before integrating Juno Analytics into your app or website, you need to create an Orbiter - the analytics container that collects anonymous usage data. Here's a step-by-step guide to get started: 1. Sign in to the Juno [Console](https://console.juno.build) 2. Navigate to [Analytics](https://console.juno.build/analytics/) 3. Click on **Get started** 4. Confirm by selecting **Create analytics** 5. (Optional) In **Advanced Options**, choose a European subnet if you want your data stored in Europe 6. Once the setup completes, click **Close** to exit the wizard 🎉 You've now created your Analytics Orbiter! But you're not done yet — you still need to tell it which Satellites (apps) can send data. 🛠 **Final Step: Setup Tracking** Go to the [Setup](https://console.juno.build/analytics/?tab=setup) tab in the Analytics page and select which Satellites should be allowed to track page views and events. --- ## Setup There are two ways to integrate Juno Analytics into your project: 1. Using your favorite package manager (`npm`, `yarn`, `pnpm`). ([Learn how](#1-with-package-manager)). 2. Without installation by fetching the library from a CDN. ([Learn how](#2-from-a-cdn)). --- ### 1\. With Package Manager Follow these steps to install and initialize the SDK using your preferred package manager. #### Install the Library To install the analytics library, run the following command: * npm * yarn * pnpm ``` npm i @junobuild/analytics ``` ``` yarn add @junobuild/analytics ``` ``` pnpm add @junobuild/analytics ``` #### Configure If you're using the [Next.js](/docs/reference/plugins.md#nextjs-plugin) or [Vite](/docs/reference/plugins.md#vite-plugin), you can define your configuration in your `juno.config` file. juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist" }, orbiter: { ids: { production: "aaaa-bbbbb-ccccc-ddddd-cai" // <-- Replace with your ID } }}); ``` If you're not using a plugin, you can skip this step and instead provide the IDs manually when initializing the Orbiter (see next section). #### Initialize ✅ Using plugins and config Just call `initOrbiter()` as early as possible in your app startup: ``` import { initOrbiter } from "@junobuild/analytics";initOrbiter(); ``` 🛠 Without plugins Pass your Satellite and Orbiter IDs manually: ``` import { initOrbiter } from "@junobuild/analytics";initOrbiter({ satelliteId: "", // replace with your Satellite ID orbiterId: "" // replace with your Orbiter ID}); ``` --- ### 2\. From a CDN If you don't want to - or cannot - install anything locally, you can load the SDK directly from a CDN. Add the following script to your HTML (for example, in `index.html`). This will fetch the library from [jsDelivr](https://www.jsdelivr.com/) and start the analytics when someone loads your site: ``` ``` --- ## Optional Features The SDK includes a few optional features you can enable to enrich your analytics. By default, these are disabled to keep your bundle small and your app fast. --- ### UA Parser By default, the library uses a naive approach to analyze the user agent string — enough to detect general categories (like mobile vs desktop) — while keeping the bundle lean and fast. If you need more detailed insights such as browser name, OS, or device model, you can opt in to use a full UA parser. #### What It Adds When enabled, the parser collects: * Browser name and version * Operating system * Device type (e.g., mobile, desktop, tablet) These enrich the stats visible in the dashboard, including OS and better browser breakdowns. #### Why It's Opt-In * Adds a few extra kilobytes to the app bundle * Disabled by default to preserve performance and minimize boot time **Note:** A more complete UA parsing approach could be performed inside a container, but this would currently require too many resources impacting both performance and cost. Delegating it to the frontend keeps things fast and efficient. #### How to Enable Pass `userAgentParser: true` when calling `initOrbiter()`: ``` import { initOrbiter } from "@junobuild/analytics";initOrbiter({ options: { userAgentParser: true }}); ``` --- ### Performance Metrics Juno Analytics supports tracking key performance metrics using [Web Vitals](https://github.com/GoogleChrome/web-vitals). This feature is **opt-in** and requires configuration in both the Console and your app's code. #### Key Metrics When enabled, the following Web Vitals are tracked: * **Time to First Byte (TTFB)**: Measures the time it takes for the first byte of data to reach the user's browser, indicating server responsiveness. * **First Contentful Paint (FCP)**: Marks the time when the first piece of content is rendered, helping assess initial loading speed. * **Largest Contentful Paint (LCP)**: Tracks the time when the largest content element becomes visible, indicating when the main content is likely fully loaded. * **Cumulative Layout Shift (CLS)**: Quantifies unexpected layout shifts during loading, reflecting visual stability. * **Interaction to Next Paint (INP)**: Measures the latency of interactions, such as clicks, to evaluate application responsiveness. #### How to Enable Web Vitals To start collecting performance metrics, you need to enable it in two places: 1. **In the Console** Go to your Orbiter's [Setup tab](https://console.juno.build/analytics/?tab=setup) and click "Edit Configuration". Enable the "Web Vitals" option under the "Advance Options" to allow the Orbiter to store performance data. 2. **In your App** Enable Web Vitals in the SDK during initialization. This ensures that the additional logic is only loaded when needed, helping keep your app's initial load size minimal. ``` import { initOrbiter } from "@junobuild/analytics";initOrbiter({ options: { performance: true }}); ``` --- ## Best Practices Here are some useful tips for working with the analytics. ### Production vs Development While the example above shows analytics being initialized in all cases, it's recommended to **disable analytics during local development**. This prevents test data from polluting your metrics if your local environment is connected to production, and avoids errors when analytics aren't set up locally which is often the case during development. ``` if (DEV) { return;}initOrbiter(); ``` ### Use Environment-Specific IDs You can also configure different IDs for different environments (e.g., development and production): juno.config.js ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist" }, orbiter: { ids: { production: "aaaa-bbbbb-ccccc-ddddd-cai", development: "ffff-eeee-ddddd-ccccc-cai" } }}); ``` --- # Source: https://juno.build/docs/reference/emulator/skylab.md # Skylab The [junobuild/skylab](https://hub.docker.com/r/junobuild/skylab) image is an all-in-one emulator for local development. It bundles everything you need to build, test, and explore the Juno ecosystem: * ✅ Juno Console (backend + UI) * 🛰️ Satellites (support for multiple application containers) * 📊 Orbiter (analytics and tracking module) * ⚙️ Supporting infrastructure (see table below) This container mounts an [Internet Computer](https://internetcomputer.org/) Replica and `icx-proxy` within a sandbox. Once ready, a custom-built CLI takes care of deploying and setting up the modules during the first boot. It also actively watches a shared folder, allowing you to live reload serverless functions written in Rust or TypeScript. This container replicates the production experience locally. That's why, when building your project with it, you'll need to create your Satellites for testing through the Console UI, just as you would in production. --- ## Configuration Skylab requires minimal configuration. Since the Console UI is used to create your Satellite, the only step is to reference the correct Satellite ID in your project’s config file. You can specify this ID under the `development` key in your Juno Config file: juno.config.ts ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { development: "", production: "" }, source: "dist", predeploy: ["npm run build"] }}); ``` For more advanced options like customizing ports, image name, or CI setup, see the [Emulator Configuration](/docs/reference/configuration.md#emulator-configuration) section. --- ## Accessing the Console UI When running Skylab, the Console UI is available at [http://localhost:5866](http://localhost:5866). This is the same interface used in production at [console.juno.build](https://console.juno.build), allowing you to create Satellites and Orbiters, inspect your wallet, manage your Datastore and Storage, etc. --- # Source: https://juno.build/docs/management/snapshots.md # Snapshots Snapshots are an essential component of any disaster recovery strategy. In the fast-paced world of development, unexpected issues can arise—such as accidental overwrites of critical data or bugs in updates. While these scenarios can't always be avoided, their impact can be minimized or mitigated. The Snapshot feature acts as your safety net, ensuring that your project can recover quickly and efficiently from potential disasters. Each snapshot is a snapshot of your module (Satellite, Mission Control, or Orbiter) at a specific point in time. Snapshots enable you to restore your module to its previous state, protecting your work and averting potential crises. --- ## How It Works You can manually create, restore, and delete snapshots for each module as needed. To do so, navigate to a module in the [console](/docs/terminology.md#console) and locate the features within the "Setup" tab. Snapshots are also automatically created during the upgrade process, capturing a snapshot when upgrading to a new version. If preferred, you can opt out in the advanced options to skip creating a snapshot or prevent overwriting an existing one. However, given the sensitivity of such processes, we strongly recommend always having a snapshot available or at least ensuring a way to restore your data—for example, by being prepared to redeploy your application quickly. Snapshots can also be [downloaded and uploaded](/docs/reference/cli.md#snapshot) offline using the CLI, allowing you to store them externally and re-import them later if needed. --- ## Limitations Snapshots are stored on the network, and the cost of a snapshot's memory consumption is charged to the module itself. This means they follow the lifecycle of your modules — if the module is deleted or runs out of cycles, its snapshot is also removed. Each module is currently limited to one snapshot at a time. This approach offers a balance between flexibility and cost-efficiency, providing a reliable recovery point without unnecessary network storage costs. If the need for multiple snapshots arises in the future, support may be expanded. Reach out and let us know. This is why snapshots should not be mistaken for backups. Unlike true backups, they do not provide historical retention, off-chain storage, or protection against accidental loss of control. For long-term data protection, external backups — such as secure cold storage for sensitive data — are recommended. With the ability to download snapshots offline, you can create your own backup routine, for example, keeping copies in secure storage for long-term protection. --- ## Frequency of Snapshots Snapshots are automated during code upgrades, with the option to opt out. Alternatively, snapshots can be managed manually. --- ## Advanced Use In addition to standard recovery, snapshots can also be uploaded to reapply the code and state from one module to another. For example, you can download a snapshot from Satellite A and use it to replace Satellite B. This should be used carefully though, as snapshots also include elements such as public access keys and user IDs. Applying one module's snapshot to another may cause unintended side effects. --- # Source: https://juno.build/docs/start-a-new-project.md # Start a New Project With Juno, a project typically lives in a single repository — combining your frontend, serverless functions, and configuration. Whether you're starting from scratch or extending an existing app, the result is a full-stack project that deploys as a single container. --- ## 🧭 Choose Your Starting Point There are multiple ways to start a Juno project. Pick what fits best: * ([Use a Juno Template](#-scaffold-with-a-juno-template)) if you want everything preconfigured * ([Bring Your Own Framework](#-start-with-your-favorite-framework)) if you’ve already picked a stack * ([Add Juno to an Existing Project](#-add-juno-to-an-existing-project)) for incremental adoption --- ## 🚀 Scaffold with a Juno Template One way to get started is by scaffolding a full-stack project using our prebuilt templates — it sets up your frontend framework of choice along with serverless functions and emulator support. To create a new project, just run: * npm * yarn * pnpm ``` npm create juno@latest ``` ``` yarn create juno ``` ``` pnpm create juno ``` **Note:** Supports Astro, Next.js, React, SvelteKit, Vue, and Angular. --- ## ✨ Start with Your Favorite Framework Prefer to begin with `npx create-next-app`, `npm create svelte@latest`, or any other starter you know well? Totally fine. Set up your frontend however you like, then bring in Juno afterward. **SSR not supported:** Juno doesn’t yet support Server Side Rendering (SSR). Your frontend code should run on the client side. We recommend using Static Site Generation (SSG) or prerendering instead. Once your app is ready, head over to the [SDK Setup Guide](/docs/setup-the-sdk.md) to: * Install the SDK * Enable emulator support * Add serverless functions * Configure deployment This gives you full flexibility while keeping everything in one repo. --- ## 🧩 Add Juno to an Existing Project Already have a project in development or production? You can integrate Juno incrementally. Start with the [SDK Setup Guide](/docs/setup-the-sdk.md) and bring in only what you need — whether that's authentication, datastore, serverless functions, or all of the above. --- ## One Repo, One App No matter how you start, Juno follows a simple principle: **one project = one repo = one container**. Everything — frontend, backend, and app state — is bundled into a single WebAssembly (WASM) container and deployed together. This architecture keeps development and deployment straightforward, reliable, and fully yours. --- # Source: https://juno.build/docs/guides/sveltekit.md # Source: https://juno.build/docs/examples/frontend/sveltekit.md # SvelteKit Example This project is a note-taking app template built with **SvelteKit**, **TypeScript**, and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template sveltekit-example ``` Source: [github.com/junobuild/create-juno/templates/sveltekit-example](https://github.com/junobuild/create-juno/tree/main/templates/sveltekit-example) --- ## Folder Structure ``` sveltekit-example/├── static/ # Static assets├── src/│ ├── lib/ # SvelteKit components, stores, types, etc.│ ├── routes/ # SvelteKit routes and layouts│ ├── app.css # Tailwind CSS styles│ └── app.html # SvelteKit HTML template├── juno.config.ts # Juno Satellite configuration├── package.json # Project dependencies and scripts├── vite.config.ts # Vite build configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **src/routes/+layout.svelte**: Main layout, initializes Juno Satellite, wraps content in authentication. * **lib/components/**: Contains UI and logic for authentication, notes table, modal, banner, etc. * **lib/types/note.ts**: TypeScript interface for notes. * **lib/types/user.ts**: TypeScript interface for user. --- ## Data Structure * **Note** (`src/lib/types/note.ts`): ``` export interface Note { text: string; url?: string;} ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in TypeScript and SvelteKit components/stores. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/routes/+layout.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/routes/+layout.svelte) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/lib/components/Auth.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Auth.svelte) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/lib/components/Login.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Login.svelte) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/lib/components/Logout.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Logout.svelte) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/lib/components/Table.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Table.svelte) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/lib/components/Modal.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Modal.svelte) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/lib/components/Delete.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Delete.svelte) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/lib/components/Modal.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Modal.svelte) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/lib/components/Delete.svelte`](https://github.com/junobuild/create-juno/blob/main/templates/sveltekit-example/src/lib/components/Delete.svelte) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/terminology.md # Terminology In Juno, we use some terms that may be unfamiliar to some. This page provides a summary of the most commonly used terms. ## Canister A canister is the term for a container on the Internet Computer. It includes both logic and state (memory), bundled together and deployed as a WebAssembly (WASM). All ([modules](#modules)) in Juno — such as ([satellites](#satellite)), ([mission controls](#mission-control)), and ([orbiters](#orbiter)) — are canisters under the hood. ## Console The "console" refers to Juno's administration application, located at [https://console.juno.build](https://console.juno.build). ## Controller On the Internet Computer, a controller is a ([principal](#principal)) (such as a user or service) that has full administrative control over a deployed module. In earlier versions of Juno, the term _controller_ was used to describe access permissions to [mission controls](/docs/terminology.md#mission-control), [satellites](/docs/terminology.md#satellite) and [orbiters](/docs/terminology.md#orbiter). This concept has since been replaced by access keys, which provide more flexibility and support for different roles. For current usage and setup, refer to the [Access Keys documentation](/docs/miscellaneous/access-keys.md). ## Cycles Cycles are used to pay for [infrastructure](/docs/miscellaneous/infrastructure.md) usage. Your [satellite](/docs/terminology.md#satellite), [mission control](/docs/terminology.md#mission-control) or [orbiter](/docs/terminology.md#orbiter) consume cycles while they are active. The amount of cycles available determines whether a module will be active, inactive, or eventually decommissioned (deleted). This ensures that related costs cannot surpass the amount of cycles available. Think of cycles like prepaid mobile data: * Just like your mobile plan allows you to make calls and browse the internet, cycles enable your containers to process computations and store data. * When your data (cycles) runs out, your service becomes inactive. * To keep your modules running smoothly, you need to top up your cycles regularly (manually or automatically). * If you don’t top it up, after some time, it will be decommissioned, similar to losing your prepaid number due to prolonged inactivity. ## Doc "doc" is a commonly used shorthand in Juno for a "document of the Datastore". Wherever you see the term "doc" in the codebase or documentation, it refers specifically to a document entity managed by the [Datastore](/docs/build/datastore.md). This abbreviation is used for brevity and consistency throughout the project. ## Internet Identity [Internet Identity](https://internetcomputer.org/internet-identity) is a decentralized authentication provider that offers a secure blockchain login experience with a user-friendly Web2 interface. It is free and passwordless. It integrates WebAuthn for maximum compatibility and, unlike other Web3 authentication solutions, it does not require you to save a private key on your device or in an application. ## Mission control Mission Control is an optional monitoring service. When enabled, it automatically monitors and tops up your Satellites and Orbiters to keep them running smoothly. Think of it like the command center for a space mission. Just as NASA's Mission Control monitors spacecraft and Satellites, your Mission Control watches over all your modules and ensures they have the resources they need. ## Modules A module — such as a Satellite, Mission Control, or Orbiter — is a container compiled into WebAssembly (WASM) and deployed on the Internet Computer with Juno. It acts as a comprehensive entity, encompassing memory, permission checks, and other Juno abstractions. These serve as endpoints that developers and users can query for various functionalities. ![A really high level schema representing a Satellite architecture](/assets/images/satellite-09d7ff40ba0d777f933e75c11863746b.png) ## Orbiter An Orbiter is an optional module you can enable for analytics. It helps you gather valuable, anonymous insights about your users. ## Principal Principals are generic identifiers for the [console](/docs/terminology.md#console), [mission controls](/docs/terminology.md#mission-control), [satellites](/docs/terminology.md#satellite), and users. They consist of a public-private key pair. When displayed or used as a configuration value, the public ID of the principal is used. Learn more about [principals](https://internetcomputer.org/docs/current/references/ic-interface-spec#principal). ## Satellite A Satellite is a container for your application. It holds your project’s data, storage, application bundle, and assets. Each Satellite is commonly dedicated to a single application. ## Subnet A subnet is like a group of programs working together on the Internet Computer. These groups, or subnets, are designed to distribute the workload across the network. By having multiple subnets, the Internet Computer can handle more activity, process data faster, and ensure the system remains efficient and secure. When you create a module, like a Satellite, it's deployed on the same subnet as the Juno Console by default: [6pbhf-qzpdk-kuqbr-pklfa-5ehhf-jfjps-zsj6q-57nrl-kzhpd-mu7hc-vae](https://dashboard.internetcomputer.org/subnet/6pbhf-qzpdk-kuqbr-pklfa-5ehhf-jfjps-zsj6q-57nrl-kzhpd-mu7hc-vae). Communicating between modules on different subnets takes longer due to the extra steps required for coordination (about 4 additional consensus rounds in the best case). This is why placing all your interacting modules on the same subnet can lead to significant performance improvements. Think of it like a huge playground with lots of groups of kids playing different games. Each group has its own area to play, and that area is called a subnet. If you want to play with kids in your own group, it’s super fast and easy because you’re all together. But if you want to play with a kid in a different group, it might take a little longer since you have to cross the playground to reach them. By picking the right group (or subnet), everyone can play faster and have more fun. ## Wallet A wallet is your secure repository for managing and storing resources in Juno. Think of it like a prepaid account: * It holds your available resources (cycles). * It lets you allocate resources to your projects and modules - e.g. with top-up. * It's automatically created when you sign in to the Console. Your wallet is tied to your identity, which is generated when you first log in. For more information see [Wallet](/docs/miscellaneous/wallet.md) documentation. --- # Source: https://juno.build/docs/troubleshooting.md # Troubleshooting --- ### Windows Powershell If you are using Windows Powershell and encounter the following error after installing the [CLI](/docs/reference/cli.md): > The term 'juno' is not recognized as a name of a cmdlet, function, script file, or executable program. Please ensure that npm is added to your system's PATH (e.g. `C:\Users\{PC_NAME}\AppData\Roaming\npm`). --- ### Windows Not Defined Juno does not support yet Server Side Rendering at the moment. Therefore, if you are facing such an issue as `ReferenceError: window is not defined` please make sure that your application is not build using SSR. We generally recommend using Static Site Generation (SSG) / prerendering. --- ### ReferenceError: global is not defined The Juno JavaScript libraries rely on the DFINITY [agent-js](https://github.com/dfinity/agent-js/) libraries to interact with the Internet Computer. These libraries require various Node.js polyfills for the browser, which unfortunately make the bundle heavier. The templates provided by Juno - `npm create juno@latest` - are preconfigured to handle this limitation and issue. However, you might encounter errors if your app bundler is not properly configured. The most common error is global not being available on the client side: ``` ReferenceError: global is not definedat new _Decoder (chunk-3K6K3FD6.js?v=df0b7a78:4968:30)at new Uint8ArrayDecoder (chunk-3K6K3FD6.js?v=df0b7a78:7475:25)at decode2 (chunk-3K6K3FD6.js?v=df0b7a78:7488:19)at _HttpAgent.readState (chunk-3K6K3FD6.js?v=df0b7a78:14483:31)at async chunk-3K6K3FD6.js?v=df0b7a78:15075:26at async Promise.all (:5173/index 0)at async Module.request (chunk-3K6K3FD6.js?v=df0b7a78:15169:3)at async _HttpAgent.syncTime (chunk-3K6K3FD6.js?v=df0b7a78:14532:22)at async Promise.all (:5173/index 0) ``` To resolve this issue, you can configure your bundler to polyfill the required libraries. Since the CLI provides support for most popular frameworks, you might find a proper configuration for your project by referring to the corresponding technology project in this repository: [https://github.com/junobuild/create-juno/tree/main/templates](https://github.com/junobuild/create-juno/tree/main/templates) --- ### ENOENT: no such file or directory When encountering the following error after running `juno hosting deploy`, it is likely caused by either not starting the command from the root directory of your project or having an incorrect configuration for the [source](/docs/build/hosting/configuration.md#source) option, which Juno uses to locate the files for deployment. > An unexpected error happened 😫. Error: ENOENT: no such file or directory, scandir ... Make sure these two requirements are correctly met before restarting the command line. --- ### A Satellite ID is not configured. Juno cannot be initialized. If you encounter the error: > A Satellite ID is not configured. Juno cannot be initialized. This means `initSatellite()` from the SDK is being called without a proper configuration. Most likely, the plugin responsible for loading your `juno.config` file values isn't set up correctly or is missing entirely. To resolve this issue, make sure your SDK is correctly configured by following the steps in the documentation: [Setup SDK > Configuration](/docs/setup-the-sdk.md#configuration) --- ### Invalid character: "<" When you scaffold an app with a template, the `juno.config` file includes placeholder values for the Satellite IDs: ``` import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { development: "", production: "" }, source: "dist" }}); ``` If you start your frontend development server without replacing these placeholders, you may encounter an error like: `Invalid character: "<"` while running your app in the browser. This happens because the app tries to parse the config at runtime and encounters the invalid placeholder character `<` in the ID values. Continue with your setup or tutorial until you receive your actual Satellite ID(s). Once you’ve updated the config with real values, make sure to restart your development server. **Note:** Note: `vite` may cache the configuration — if the error persists after updating the file, try restarting the dev server with the `--force` flag or make a small code change to trigger a rebuild. --- ### My Heap Memory Keeps Growing — Is That Expected? If your heap memory usage keeps increasing and doesn't go down, even after deleting data — [this is expected behavior](/docs/miscellaneous/memory.md#behavior). See the documentation for why this happens and how to manage it effectively. --- # Source: https://juno.build/docs/reference/functions/typescript.md # Source: https://juno.build/docs/guides/typescript.md # Source: https://juno.build/docs/examples/functions/typescript.md # Source: https://juno.build/docs/build/functions/development/typescript.md # TypeScript This page covers advanced options for writing serverless functions in TypeScript. --- ## Maintenance Since your project includes all Satellite features, it's essential to stay in sync with Juno’s updates to maintain compatibility. Always check the [releases](https://github.com/junobuild/juno/releases) page for the latest changes, and update your local container image (source [repo](https://github.com/junobuild/juno-docker)) accordingly to ensure you're running the latest runtime and features. **Caution:** Always upgrade iteratively and avoid skipping version numbers. While we strive to minimize breaking changes, it's crucial to upgrade through each released version sequentially. For example, if you're on **v0.0.23** and the latest release is **v0.0.26**, first upgrade to **v0.0.24**, then **v0.0.25**, and finally **v0.0.26**. Skipping versions could lead to unexpected issues. --- ## Versioning When writing serverless functions in TypeScript, Juno uses the version defined in your project’s `package.json`. This version is embedded into the compiled Wasm module and shown in the Juno Console, making it easier to keep track of deployments. By default, the version is inherited from the root-level `version` field: ``` { "name": "demo", "version": "0.0.10"} ``` However, if you want to version your functions independently from your app or workspace, you can define a custom version field specifically for Juno Functions: ``` { "name": "demo", "version": "0.0.10", "juno": { "functions": { "version": "0.0.4" } }} ``` This version is embedded into the compiled Wasm binary and displayed in the Juno Console. It helps you: * Track which version of your serverless logic is currently deployed. * Debug more effectively by matching behavior in the Console with specific code versions. * Move independently of Juno updates — you're in full control of your own function versioning. You can use any versioning scheme that suits your development workflow (e.g. `0.1.0`, `1.0.0-beta`, `2025.04.18`...). --- # Source: https://juno.build/docs/guides/github-actions/upgrade-functions.md # Upgrade Serverless Functions (Optional) **Caution:** We do not recommend upgrading your container directly from CI in **production**. This approach hands over control to automation, which may not be suitable for critical environments. Prefer a change workflow and executing the upgrade with your CLI or in the Console UI. --- ## Configuration To configure an action to upgrade your Satellite container, follow these steps: 1. Create an `upgrade.yml` file in the `.github/workflows` subfolder of your repository. 2. Paste the following code into the file: * npm * yarn * pnpm .github/workflows/upgrade.yml ``` name: Upgrade Satellite Containeron: workflow_dispatch:jobs: upgrade: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Install Dependencies run: npm ci - name: Build uses: junobuild/juno-action@full with: args: functions build - name: Upgrade uses: junobuild/juno-action@full with: args: functions upgrade env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/upgrade.yml ``` name: Upgrade Satellite Containeron: workflow_dispatch:jobs: upgrade: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - name: Enable Corepack run: corepack enable - name: Activate Yarn run: corepack prepare yarn@1.x --activate - name: Install Dependencies run: yarn install --frozen-lockfile - name: Build uses: junobuild/juno-action@full with: args: functions build - name: Upgrade uses: junobuild/juno-action@full with: args: functions upgrade env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` .github/workflows/upgrade.yml ``` name: Upgrade Satellite Containeron: workflow_dispatch:jobs: upgrade: runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" - uses: pnpm/action-setup@v4 with: version: 10 - name: Install Dependencies run: pnpm i --frozen-lockfile - name: Build uses: junobuild/juno-action@full with: args: functions build - name: Upgrade uses: junobuild/juno-action@full with: args: functions upgrade env: JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }} ``` --- # Source: https://juno.build/docs/build/authentication/utilities.md # Authentication Utilities These utilities work with **any authentication provider**. They let you manage user sessions, react to authentication changes, and access identities for advanced use cases. --- ## Sign-out You can end a user's session, no matter which provider they used to sign in, by logging them out. ``` import { signOut } from "@junobuild/core";await signOut(); ``` By default, the page will automatically reload after a successful sign-out. This is a common pattern in logout flows that ensures the application restarts from a clean state. If you wish to opt out, the library does clear its internal state and authentication before the reload, and you can use the `windowReload` option set to `false`. ``` import { signOut } from "@junobuild/core";await signOut({ windowReload: false }); ``` --- ## Listening to Auth Changes You can monitor when a user signs in or out using `onAuthStateChange`. It gives you the current user and notifies you whenever their authentication state changes. ``` import { onAuthStateChange } from "@junobuild/core";// Reactively track if the user is signed in or signed outonAuthStateChange((user: User | null) => { console.log("User:", user);}); ``` If you register the subscriber at the top of your application, it will automatically reflect the user's state: * `null` when the app first loads and the user is not signed in * A `User` object when they sign in or refresh while authenticated * `null` again when they sign out To stop listening, you can call the unsubscribe function returned: ``` import { onAuthStateChange } from "@junobuild/core";const unsubscribe = onAuthStateChange((user: User | null) => { console.log("User:", user);});// Stop listeningunsubscribe(); ``` --- ## Imperative Access to Identity For advanced use cases, you may need direct access to the user's identity. You can use `getIdentityOnce` to retrieve the identity if the user is currently authenticated. **Caution:** Use this function **imperatively only**. Do **not** persist the identity in global state or store it for reuse. This function is intended for short-lived, one-time operations only. ``` import { getIdentityOnce } from "@junobuild/core";// Returns null if the user is not authenticatedconst identity = await getIdentityOnce();if (identity !== null) { // Use the identity to perform calls on the Internet Computer} ``` Typical use case for this function is to enable developers to implement custom features for the Internet Computer: * Passing the identity to temporarily create an actor or agent to call a canister * Signing a message or making a one-time authenticated call --- ## Session Expiration To proactively detect when a session duration expires, you can use the pre-bundled Web Worker provided by Juno's SDK. To do so, you can follow these steps: 1. Copy the worker file provided by Juno's SDK to your app's static folder. For example, to your `public` folder with a NPM `postinstall` script: ``` { "scripts": { "postinstall": "node -e \"require('fs').cpSync('node_modules/@junobuild/core/dist/workers/', './static/workers', {recursive: true});\"" }} ``` Once configured, run `npm run postinstall` manually to trigger the initial copy. Every time you run `npm ci`, the post-install target will execute, ensuring the worker is copied. 2. Enable the option when you initialize Juno: ``` import { initSatellite } from "@junobuild/core";await initSatellite({ workers: { auth: true }}); ``` The `auth` option can accept either `true`, which will default to using a worker located at [https://yourapp/workers/auth.worker.js](https://yourapp/workers/auth.worker.js), or a custom `string` to provide your own URL. When the session expires, it will automatically be terminated with a standard [sign-out](/docs/build/authentication/utilities.md#sign-out). Additionally, an event called `junoSignOutAuthTimer` will be thrown at the `document` level. This event can be used, for example, to display a warning to your users or if you wish to reload the window. ``` document.addEventListener( "junoSignOutAuthTimer", () => { // Display an information to your users }, { passive: true }); ``` The worker also emits an event named `junoDelegationRemainingTime`, which provides the remaining duration in milliseconds of the authentication delegation. This can be useful if you want to display to your users how much time remains in their active session. ``` document.addEventListener( "junoDelegationRemainingTime", ({ detail: remainingTime }) => { // Display the remaining session duration to your users }, { passive: true }); ``` --- # Source: https://juno.build/docs/reference/functions/typescript/utils.md # Source: https://juno.build/docs/reference/functions/rust/utils.md # Utils The following utilities are provided to help you work with document and asset data inside your Satellite. They simplify tasks such as decoding and encoding data, serializing custom types, and interacting with Juno’s core features in a consistent way. **📦 Crate:** All utilities on this page are provided by the [junobuild-utils](https://docs.rs/junobuild-utils/latest/junobuild_utils/index.html) crate. To use them, add this to your Cargo.toml: ``` [dependencies]junobuild-utils = "*" ``` Replace `*` with the specific version you want to use, or omit the version to always use the latest version. --- ## decode\_doc\_data Deserializes raw document data (`&[u8]`) into a typed Rust struct. Use this inside hooks or assertions to get the document contents in a strongly typed way. ``` pub fn decode_doc_data Deserialize<'a>>( data: &[u8],) -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-utils/latest/junobuild_utils/fn.decode_doc_data.html) --- ## encode\_doc\_data Serializes a Rust struct into a `Vec` for storing a document into the datastore. Use this when modifying or creating document data inside a hook or assertion. ``` pub fn encode_doc_data(data: &T) -> Result, String> ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-utils/latest/junobuild_utils/fn.encode_doc_data.html) --- ## encode\_doc\_data\_to\_string Serializes a Rust struct into a JSON String. Use this if you want to store or inspect document data in a readable format. Commonly used when exposing JSON data on the web, for example by reproducing documents from the datastore into the storage. ``` pub fn encode_doc_data_to_string( data: &T,) -> Result ``` 📦 See full definition on [docs.rs](https://docs.rs/junobuild-utils/latest/junobuild_utils/fn.encode_doc_data_to_string.html) --- # Source: https://juno.build/docs/examples/frontend/vanilla-javascript.md # Vanilla JavaScript Example This project is a note-taking app template built with **vanilla JavaScript** and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template vanilla-js-example ``` Source: [github.com/junobuild/create-juno/templates/vanilla-js-example](https://github.com/junobuild/create-juno/tree/main/templates/vanilla-js-example) --- ## Folder Structure ``` vanilla-js-example/├── public/ # Static assets├── src/│ ├── components/ # JS UI components (auth, table, modal, banner, etc.)│ ├── main.js # Main entry point│ └── style.css # Tailwind CSS styles├── juno.config.mjs # Juno Satellite configuration├── package.json # Project dependencies and scripts├── vite.config.js # Vite build configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **src/main.js**: Main entry point, initializes Juno Satellite, handles authentication state. * **components/**: Contains UI and logic for authentication, notes table, modal, banner, etc. --- ## Data Structure * **Note** (used in table.js, modal.js, etc.): ``` // Example note object{ key: string, data: { text: string, url?: string }} ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.mjs` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * **juno.config.mjs**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.js**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update `juno.config.mjs` with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in vanilla JavaScript modules. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/main.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/main.js) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/main.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/main.js), [`src/components/modal.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/modal.js) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/components/login.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/login.js) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/components/logout.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/logout.js) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/components/table.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/table.js) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/components/modal.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/modal.js) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/components/delete.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/delete.js) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/components/modal.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/modal.js) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/components/delete.js`](https://github.com/junobuild/create-juno/blob/main/templates/vanilla-js-example/src/components/delete.js) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/comparison/vs-heroku.md # What makes Juno a great Heroku alternative Heroku introduced a simple way to deploy apps — push code, and it ran in the cloud. It remains a solid choice for long-running, traditional web applications. But today's stack is different. Modern apps favor lightweight deployments, usage-based execution, and infrastructure that doesn't require maintaining always-on containers. Juno brings back Heroku-style simplicity for the modern era — giving you your own execution environment with no servers to manage and no platform control over your app. --- ## The Trade-Off: Always-On Containers vs Modern Execution Heroku runs long-lived app containers. This works well for classic backend apps, but means: * You pay for uptime, even when idle * You manage long-running processes * Operational responsibility increases over time With Juno, you still deploy your app — but it runs in a self-contained environment on demand, with no OS, runtime patching, or server process to maintain. * **You own the deployment** * **No server or container administration** * **No platform access to your code or data** Same simplicity — modern execution. --- ## Feature Comparison | Feature | Heroku (Traditional PaaS) | Juno (Modern Serverless) | | --- | --- | --- | | Architecture | Always-on containers (dynos) | Self-contained containers, executed on demand | | Deployment | Git push | CLI or Git-based deploy | | Maintenance | App + container upkeep | You deploy updates; no OS to maintain | | Data / Storage | Add-ons | Built-in datastore & storage (optional) | | Authentication | External add-ons | Built-in decentralized auth (optional) | | Core Benefit | Classic simplicity | Ownership, modern workflow, no server overhead | > **Note:** Juno isn't for persistent background workers or long-running processes. It's optimized for modern web apps. --- ## Cost Considerations Heroku is easy to start with, but costs rise as your app grows — especially if it needs background processes, add-ons, or multiple environments. Juno keeps things simple. You pay for your own isolated app environment and the resources it actually uses over time — no per-feature charges, no surprise jumps, no scaling tax. This means: * Costs stay steady as your project evolves * No extra fees for enabling auth, data, or functions * You keep full control over how your app runs and spends For long-term projects, Juno provides stability, ownership, and clarity — without managing servers and without unpredictable pricing. --- ## When Juno Makes the Most Sense **Ideal for:** * Modern apps, dashboards, APIs, documentation sites * Teams who want Heroku-style simplicity without servers * Builders who value ownership and platform independence * Projects that don't require persistent processes **Heroku still fits when:** * You need a long-running application server * You're operating a legacy stack * Your app has background jobs attached to the runtime --- ## The takeaway Heroku pioneered simple cloud deployment. Juno builds on that spirit — but for modern workloads and developers who want ownership, privacy, and a lightweight execution model without managing infrastructure. If you love Heroku's simplicity but want a platform designed for the next decade, Juno is a natural evolution. --- ## Ready to try Juno? Ready to explore Juno? [Start building](/docs/intro.md) --- # Source: https://juno.build/docs/comparison/vs-netlify.md # What makes Juno a great Netlify alternative Netlify has long been a go-to platform for frontend developers. It pioneered the Jamstack movement, offers smooth Git-based workflows, and makes shipping static sites fast and simple. But as projects mature, needs evolve. Ownership starts to matter. Data and infrastructure control matter. Cost predictability matters. And having the freedom to run your application independently becomes increasingly important. This is where Juno steps in. Juno provides the same simple deployment experience for static sites — but runs your project in a container you own, with full control over its execution. It's the convenience of managed infrastructure with the control of self-hosting. --- ## The Trade-Off: Convenience vs Control Netlify's strength is its fully managed, centralized hosting. It handles everything, which is great — until you need: * Guarantees around application independence * Confidence your project can't be taken offline by a provider * Predictable long-term pricing * Ownership over your data and runtime Juno flips the model. You get the same simple “git push to deploy” flow, but you run your app in your own execution environment — without managing servers or ops. * **Your Own Hosting Container** — Your site runs in a container you own and control. No black-box environment. * **Unstoppable Delivery** — Hosted across independent nodes. No single provider can restrict or remove your project. Same simplicity — more control. --- ## Feature Breakdown: Netlify's Jamstack vs Juno's Stack | Feature | Netlify (Managed Jamstack) | Juno (Owned Execution) | | --- | --- | --- | | Deployment | Global CDN (Centralized) | Decentralized Containers (User-owned) | | Static Hosting | Yes — fast and convenient | Yes — same simplicity, but with ownership | | Functions | Lambda-based (Optional Add-on) | Rust/TypeScript Functions (Optional, Native) | | Authentication | Netlify Identity (Add-on) | Built-in Privacy-First Auth (Optional) | | Data / Storage | Add-ons (Forms, Large Media) | Built-in Datastore & Storage (Optional) | | Core Benefit | Convenience & speed | Ownership, stability, independence | > **Important:** This comparison focuses on static hosting. Juno also offers integrated backend services, but you can adopt them only if/when needed. --- ## Cost Advantage: Predictable & Transparent Pricing Netlify's free tier is generous — but as traffic and features scale, costs can rise quickly due to: * Bandwidth overages * Build minutes * Paid add-ons (identity, serverless, large media) Juno uses a simple usage-based model. You pay for compute and storage like a utility, without surprise bandwidth charges or per-feature pricing layers. For long-running, growing projects, this creates financial predictability and independence. --- ## Simplicity First: Static Hosting Done Right Both Netlify and Juno deliver a familiar, modern developer workflow: * Git-based deployments * Support for modern frameworks (Next.js static export, Astro, SvelteKit static, Vue, React, etc.) * CLI-first developer experience The difference is that **Juno gives you ownership from day one**, with the option to add backend capabilities as your app grows — without switching platforms. Start static. Scale when you're ready. --- ## Performance Considerations Netlify's edge network is highly optimized and may have the slight edge for globally-distributed, ultra-low-latency workloads. Juno delivers competitive static performance with the benefit of independence and data sovereignty. For most sites — documentation, marketing, dashboards, landing pages — Juno provides excellent real-world performance with long-term control. --- ## When Juno Makes the Most Sense **Best fit for:** * Static sites that may evolve into full apps later * Projects where data independence and platform neutrality matter * Teams planning long-term builds who want infrastructure control * Builders who want the ease of Netlify with a clear path to autonomy **Trade-offs to consider:** * Smaller ecosystem vs Netlify's long-established plugins * SSR not supported — Juno is optimized for static + client-side apps If you're deploying a quick hobby site and don't have long-term infrastructure needs, Netlify remains a great choice. If you want the same ease — with ownership, clarity, and room to scale — Juno is a powerful Netlify alternative. --- ## Ready to try Juno? Ready to explore Juno? [Start building](/docs/intro.md) --- # Source: https://juno.build/docs/comparison/vs-railway.md # What makes Juno a great Railway alternative Railway has earned a strong reputation among developers by making deployment simple and removing infrastructure friction. It modernized the Heroku experience with a polished workflow and transparent usage-based pricing — great for teams who want to ship quickly without managing cloud resources. But what if you want that same simplicity while keeping full control over how and where your application runs? What if you want to own your environment instead of depending on someone else's platform? This is where Juno steps in — an open-source serverless platform that delivers a similar smooth development and deployment experience, but with true app ownership and privacy built in from day one. --- ## The Trade-Off: Managed Convenience vs. Ownership Railway makes the cloud feel effortless — but your app ultimately runs inside someone else's system, governed by their operational rules and platform roadmap. Juno flips that model. You get the same frictionless deployment and tooling, but your application lives in your own isolated execution environment. That brings two major benefits: * **Your application, your environment** — Juno cannot access your code, data, or infrastructure. * **Resilient by design** — Your project runs in an independent execution layer, not tied to a single commercial provider. You keep the convenience — without giving up control. --- ## Feature Breakdown: Railway's PaaS vs Juno's Owned Stack | Feature | Railway (Managed Cloud) | Juno (Owned Environment) | | --- | --- | --- | | Deployment | Fully managed cloud | Self-contained environment you own | | Backend services | External database & auth services | Built-in datastore, auth, and storage (optional) | | Functions | Container-based execution | Rust/TS serverless functions | | Data control | Platform-controlled environment | Full app and data ownership | | Core benefit | Fast modern PaaS experience | Same simplicity with long-term control | --- ## Cost Advantage: Usage Simplicity vs. Predictable Ownership Railway's metered pricing is clear and modern — you pay as your resources grow. But as your project succeeds, costs can rise and remain tied to a commercial cloud platform. Juno offers consistent, usage-based pricing in an environment that's yours. You only pay for the resources your app consumes over time — no add-on fees, no tier upgrades, and no platform-driven pricing surprises. For projects meant to run and evolve for years, this provides financial stability and confidence. --- ## Beyond Deployment: Your Full Stack, When You Need It Railway shines for deploying apps quickly. For many setups, you still need to bring your own: * Authentication * Database * Object storage * Serverless compute * Access control logic Juno includes those capabilities by default — and you can adopt them gradually. It's a full-stack environment that scales with your needs, without piecing together separate vendors or services. --- ## Performance Considerations Railway leverages centralized cloud performance and may excel in certain latency-critical workloads. Juno provides competitive real-world performance for the vast majority of modern web apps — with the added benefit of independence, stability, and private execution. If your primary goal is ultra-optimized centralized edge workloads, Railway remains strong. If you value control and long-term resilience, Juno stands apart. --- ## What You Should Know **Best fit for:** * Teams who want simplicity without platform dependence * Apps that may grow toward full-stack needs * Builders who want privacy and long-term ownership of their environment * Projects where stability and control matter more than managed cloud convenience **Trade-offs to consider:** * Smaller ecosystem vs Railway's plugin ecosystem * No traditional SSR — Juno is built for static + client-side apps --- ## The Right Choice for Your Project If you're deploying a traditional backend app and want instant PaaS convenience with managed infrastructure, Railway is a solid choice. But if your application demands: * Your own execution environment * Integrated full-stack building blocks you control * Predictable, usage-based operating costs * An open platform that gives you independence Then **Juno is a powerful Railway alternative** — all the developer convenience, without handing your app to someone else's platform. --- ## Ready to try Juno? Ready to explore Juno? [Start building](/docs/intro.md) --- # Source: https://juno.build/docs/comparison/vs-self-hosting.md # What makes Juno a great self-hosting alternative For years, developers had two choices: host everything themselves, or rely on a managed platform. Traditional self-hosting gives you full control — but also means managing servers, patching systems, setting up reverse proxies, configuring SSL, securing databases, watching logs, scaling when traffic hits, and fixing things at 2 AM. Juno gives you the control and privacy of self-hosting, without the operational overhead. You get your own execution environment and data ownership — without maintaining machines, containers, or cloud networking. --- ## Control Without the Maintenance Self-hosting means running and operating the entire stack: * Provisioning a VPS or bare metal server * OS updates and security patches * SSL and reverse proxy setup * Deployment pipelines and build tooling * Managing databases, backups, and certificates * Monitoring uptime and infrastructure health With Juno, you still control your deployments — nothing runs or changes without your action — but you don't need to manage operating systems, server processes, firewall rules, or runtime security layers. * **You own the container and trigger upgrades** * **No OS maintenance or server configuration** * **Built-in environment hardening** * **Independent execution with no third-party access** Same autonomy — dramatically less work. --- ## Feature Comparison | Feature | Traditional Self-Hosting | Juno | | --- | --- | --- | | Infrastructure | VPS / bare metal | Self-contained container (no servers) | | Setup | Manual | CLI + Git-based deployment | | Maintenance | High (patches, security, upgrades) | None (platform handles it) | | Core Services | Install & secure yourself | Built-in auth, datastore, storage | | Availability | Single server unless custom setup | Replicated across independent nodes | | Best For | Full-time operators / sysadmins | Developers who want control without ops | --- ## Cost Considerations Self-hosting looks cheap on day one, but adds ongoing hidden costs: * Time spent on ops * Downtime risk * Security responsibilities * Scaling complexity Juno uses simple usage-based pricing for compute and storage. No machines to maintain, no surprise maintenance time, no infrastructure overhead. --- ## When Juno Makes the Most Sense **Best fit for developers who want:** * Self-host-level control without running servers * A private, isolated execution environment * Built-in authentication, database, and storage * Production-grade reliability without ops work **Self-hosting still fits when:** * You enjoy running servers * You need bare-metal control * You want to manage every layer yourself --- ## The takeaway Self-hosting gives you freedom — and a lot of maintenance. Juno gives you the same ownership and control, but lets you focus entirely on building rather than operating infrastructure. If you want the privacy and autonomy of running your own server, without becoming your own DevOps team, Juno is the modern alternative. --- ## Ready to try Juno? Ready to explore Juno? [Start building](/docs/intro.md) --- # Source: https://juno.build/docs/comparison/vs-vercel.md # What makes Juno a great Vercel alternative Vercel has been a default choice for frontend teams building with Next.js. It's fast, convenient, and delivers a world-class developer experience. For teams prioritizing raw speed and integration with the centralized cloud ecosystem, Vercel is the established leader. But what if you need more than just speed? What if you need true ownership, control over your infrastructure, and a platform that won't lock you in? This is where Juno steps in. It's an open-source serverless platform to build, deploy, and run modern apps with the privacy and control of self-hosting — without the infrastructure headache. --- ## The Trade-Off: Convenience vs. Control Vercel's strength lies in its managed infrastructure. It handles everything, but that convenience comes at a cost: your application is entirely dependent on their commercial policies and centralized infrastructure. Juno flips this model. It provides a similar seamless developer experience but gives you your own self-contained execution space. This architectural difference is the key benefit for developers: * **Your Own Infrastructure**: Your application runs in a container you own and control — with zero DevOps burden. Juno has zero access to your code, data, or infrastructure. Everything runs under your ownership. * **Unstoppable Execution**: Deployed to a network of independent nodes operated by different providers worldwide, making it resistant to censorship, unexpected downtime, and single points of failure. --- ## Feature Breakdown: Vercel's Speed vs. Juno's Stack | Feature | Vercel (Centralized Speed) | Juno (Decentralized Control) | | --- | --- | --- | | Deployment | Global CDN (Centralized Cloud) | Decentralized Containers (Unstoppable) | | Serverless Functions | Edge Functions (Fast, Centralized) | Rust/TypeScript Functions (Owned, Decentralized) | | Authentication | External Services Required | Built-in Decentralized Auth (Privacy-First) | | Datastore | External Services Required | Built-in Decentralized Datastore (Owned Data) | | File Storage | External Services Required | Built-in Decentralized Storage | | Core Benefit | Speed, Convenience, Established Ecosystem | Ownership, Privacy, Integrated Full Stack | --- ## Cost Advantage: Predictable Ownership vs. Escalating Bills Vercel offers a generous free tier — but its pricing scales quickly and often unpredictably as your traffic grows. Bandwidth overages and function execution costs can lead to surprise bills as your application succeeds. Juno offers predictable, usage-based pricing with transparent costs for compute and storage. You pay for what you use like a utility, with no surprise bandwidth charges or vendor lock-in premiums. This creates cost efficiency and financial stability for growing apps. --- ## Beyond Hosting: A Full-Stack Advantage Vercel excels at frontend deployment, but often requires you to stitch together external services for a complete application — databases, file storage, functions, and more. Juno integrates these natively: * **Built-in Data & Storage** — Store app state and user-generated content without managing external services. * **Serverless Functions** — Write backend logic in Rust or TypeScript and deploy alongside your frontend. * **Familiar Developer Workflow** — Works with React, Next.js (static export), SvelteKit (static), Astro, Vue, and more. The result: modern serverless development in your own self-contained execution space — the privacy and control of self-hosting without the operational overhead. --- ## Performance Considerations Juno's decentralized network is optimized for web-speed delivery with nodes distributed globally. While Vercel's edge network is highly optimized for raw speed, Juno delivers competitive performance with the added benefit of resilience and data sovereignty. For applications where sub-50ms response times are critical (like real-time collaborative tools), Vercel's edge infrastructure may have an advantage. For most web applications, Juno provides excellent performance while giving you full ownership of your stack. --- ## What You Should Know Juno represents a different approach to web infrastructure. Here's what to consider: **Best fit for:** * Projects requiring data sovereignty and user-owned data * Privacy-focused applications where you don't want to depend on centralized providers * Long-term projects where you want infrastructure independence * Applications needing censorship resistance or unstoppable availability **Trade-offs to consider:** * Smaller (but growing) ecosystem compared to Vercel's mature marketplace * No server-side rendering (SSR) support — Juno is optimized for static sites and client-side applications **Migration path:** Juno supports standard web frameworks, making it straightforward to port existing applications. Many teams start with a proof of concept to explore the platform — getting started is free, so you can experiment without commitment before deciding to migrate. --- ## The Right Choice for Your Project If you're building a simple marketing site and need maximum speed with a large ecosystem of integrations, Vercel remains a strong choice. But if your application demands: * **Your own infrastructure** without DevOps overhead * **Full-stack services you control** (auth, data, storage, compute) * **Privacy and ownership** — Juno has zero access to your code or data * **Open-source, unstoppable execution** Then **Juno is a powerful Vercel alternative** — the same serverless experience developers love, with actual ownership and control over your application. --- ## Ready to try Juno? Ready to explore Juno? [Start building](/docs/intro.md) --- # Source: https://juno.build/docs/guides/vue.md # Source: https://juno.build/docs/examples/frontend/vue.md # Vue Example This project is a note-taking app template built with **Vue**, **TypeScript**, and **Tailwind CSS**, designed to demonstrate integration with Juno for app development. It showcases authentication, data storage, and file storage using Juno's Satellite container. You can scaffold it using the following command, or browse the source code: ``` npm create juno@latest -- --template vue-example ``` Source: [github.com/junobuild/create-juno/templates/vue-example](https://github.com/junobuild/create-juno/tree/main/templates/vue-example) --- ## Folder Structure ``` vue-example/├── public/ # Static assets├── src/│ ├── components/ # Vue UI components (Auth, Table, Modal, Banner, etc.)│ ├── stores/ # Pinia stores for auth, etc.│ ├── types/ # TypeScript types (e.g., note.ts)│ ├── App.vue # Main app component│ ├── main.ts # Vue entry point├── juno.config.ts # Juno Satellite configuration├── package.json # Project dependencies and scripts├── vite.config.ts # Vite build configuration├── README.md # User-facing documentation└── ... # Other config and build files ``` --- ## Key Features * **Juno Integration**: Uses Juno's Satellite for authentication, Datastore, and Storage. * **Authentication**: Login/logout flow. * **Notes Collection**: Users can create, view, and delete notes (text, with optional file URL). * **Images Collection**: Supports file storage for images. * **Responsive UI**: Built with Tailwind CSS for modern styling. * **Banner**: Warns if the Satellite is not configured for local development. --- ## Main Components * **src/App.vue**: Main app component, initializes Juno Satellite, wraps content in authentication. * **components/**: Contains UI and logic for authentication, notes table, modal, banner, etc. * **stores/auth.store.ts**: Pinia store for authentication state. * **types/note.ts**: TypeScript interface for notes. --- ## Data Structure * **Note** (`src/types/note.ts`): ``` export interface Note { text: string; url?: string;} ``` --- ## How to Run . **Install dependencies**: ``` npm install ``` NaN. **Start Juno local emulator**: **Important:** Requires the Juno CLI to be available `npm i -g @junobuild/cli` ``` juno emulator start ``` 3. **Create a Satellite** for local dev: * Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. * Update `juno.config.ts` with your Satellite ID. 4. **Create required collections**: * `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) * `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) 5. **Start the frontend dev server** (in a separate terminal): ``` npm run dev ``` --- ## Juno-Specific Configuration * **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. * **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. --- ## Production Deployment * Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. * Update with the production Satellite ID. * Build and deploy: ``` npm run buildjuno hosting deploy ``` --- ## Notes * The app is intended as a starting point for Juno-based projects. * All logic is in TypeScript and Vue components/stores. * The app is fully client-side (Server Side Rendering is not supported yet) and interacts with Juno via the Satellite container. --- ## Juno SDK Used The following functions from `@junobuild/core` are used in this example: | Function | Purpose/Description | Where Used (File/Component) | Juno Docs/Source Reference | | --- | --- | --- | --- | | `initSatellite` | Initialize Juno Satellite container | [`src/App.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/App.vue) | [Initialization](/docs/setup-the-sdk.md#initialization) | | `onAuthStateChange` | Subscribe to auth state changes | [`src/stores/auth.store.ts`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/stores/auth.store.ts) | [Listening to Auth Changes](/docs/build/authentication/utilities.md#listening-to-auth-changes) | | `signIn` | Sign in user | [`src/components/Login.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Login.vue) | [Sign-in](/docs/build/authentication/internet-identity.md#sign-in) | | `signOut` | Sign out user | [`src/components/Logout.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Logout.vue) | [Sign-out](/docs/build/authentication/utilities.md#sign-out) | | `listDocs` | List documents in a collection | [`src/components/Table.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Table.vue) | [List documents](/docs/build/datastore/development.md#list-documents) | | `setDoc` | Create or update a document | [`src/components/Modal.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Modal.vue) | [Add a document](/docs/build/datastore/development.md#add-a-document) | | `deleteDoc` | Delete a document | [`src/components/Delete.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Delete.vue) | [Delete a document](/docs/build/datastore/development.md#delete-a-document) | | `uploadFile` | Upload a file to storage | [`src/components/Modal.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Modal.vue) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/components/Delete.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Delete.vue) | [Delete asset](/docs/build/storage/development.md#delete-asset) | --- # Source: https://juno.build/docs/miscellaneous/wallet.md # Wallet This section provides guidance on managing your cycles with your wallet (your account), which are essential for maintaining and providing enough resources for your modules in the Juno ecosystem. **Important:** Just like your modules, your wallet is under your control — Juno cannot access, move, or recover the cycles held inside. Because of this model, there are no refunds, reversals, or recovery options. Always double-check destination addresses before sending funds. As a best practice, we recommend not holding large amounts of cycles unless necessary. Use it as a utility for fueling your modules — not as a long-term vault. We also recommend enabling [monitoring](/docs/management/monitoring.md) to ensure your projects and analytics stay alive and responsive at all times. --- ## What are Cycles? Cycles are used to pay for infrastructure usage. Your Satellite, Mission Control or Orbiter consume cycles while they are active. The amount of cycles available determines whether a module will be active, inactive, or eventually decommissioned (deleted). This ensures that related costs cannot surpass the amount of cycles available. Think of cycles like prepaid mobile data: * Just like your mobile plan allows you to make calls and browse the internet, cycles enable your containers to process computations and store data. * When your data (cycles) runs out, your service becomes inactive. * To keep your modules running smoothly, you need to top up your cycles regularly (manually or automatically). * If you don’t top it up, after some time, it will be decommissioned, similar to losing your prepaid number due to prolonged inactivity. --- ## Buying Cycles The easiest way to purchase cycles — and get the best deal — is through [Cycle.express](https://cycle.express), which lets you pay with a credit card via Stripe. The service is integrated directly into the Juno Console. From your wallet, click "Buy" and follow the steps. **Note:** The default purchase amount is $1 USD. You can change this amount on Stripe's payment page (maximum $100). ![A screenshot of where to find the call to action Buy](/assets/images/wallet-buy-fddf8fcc9927dd1923600a7e2283aeef.png) --- ## Receiving Cycles If you already hold cycles or want to swap some, you can use the [OISY Wallet](https://oisy.com). To initiate a transaction manually, you will need to provide a destination address. To find it in the [console](https://console.juno.build), open the shortcut to your [wallet](https://console.juno.build/wallet) and click "Receive" select "Wallet ID". ![A screenshot of where to find the call to action Receive](/assets/images/wallet-receive-78153f6bf10b0507baf66fb0d01fec5d.png) ![A screenshot of where to find the link to the Wallet ID](/assets/images/wallet-receive-wallet-id-b4f97e0e100bf750a8a962309f6d05df.png) You can also connect OISY to Juno's console to initiate the transaction and proceed with the approval. This eliminates the need to copy, paste, or scan any addresses. ![A screenshot of the wallet "Receive" modal with an arrow pointing to the OISY option](/assets/images/wallet-receive-oisy-a48815e1d68d20fc10c13548b53fbc69.png) --- ## Send Cycles Sending Cycles to the ecosystem or the outside world can be initiated from your wallet in Juno's [console](https://console.juno.build). To start a transaction, click "Send". **Important:** Sending cycles transfers them to another wallet. To add manually cycles (resources) to your modules (Satellites, Orbiters, or Mission Control), use the **Top-up** feature instead. ![A screenshot of the wallet with the "Send" button](/assets/images/wallet-send-966cfbae083d2287efaa23ad4a754177.png) Enter the destination wallet ID or account identifier where you want to send cycles, along with the amount. ![A screenshot of the wallet send form](/assets/images/wallet-send-form-53bc9d2aa33d85a71542462d52464313.png) Review the transaction details and confirm to execute it. ![A screenshot of the wallet send review mask](/assets/images/wallet-send-review-0d7e6b1fac55e36bdf0fe94f47dea223.png) --- ## ICP For convenience, the developer wallet can hold ICP tokens as well. When its balance is greater than zero, a conversion feature lets you easily convert them to cycles. You can also receive and send ICP for backwards compatibility with Mission Control. Cycles remain the recommended approach for all operations. --- # Source: https://juno.build/docs/miscellaneous/workarounds.md # Workarounds This page is dedicated to helping you make the most of Juno features, even when some functionalities are not yet fully supported out of the box. Below, you'll find practical workarounds and guidance for processes which in the future will be resolved by new features. --- ## Transferring a Satellite to another "Account" Although Juno does not yet support direct satellite transfers - such as if you want to hand over a project to your friends or colleagues - you can use the following steps as a workaround: #### 1\. Add the new access key to the Satellite **Danger:** Never ever add access keys to your modules without being absolutely certain of their validity. Double-check everything before performing such a procedure. In your satellite, assign the access key of the destination account with administrative permissions: * The Developer ID (available under "Preferences") In other words, ask your friend or colleague for their Developer ID, and add it as new access keys. Again, **please be absolutely certain** before adding the controllers. #### 2\. Attach Satellite in destination account The destination account — your friend or colleague — can use the "Attach Satellite" feature available in the launchpad of the [Console](https://console.juno.build) (the "Home" screen). To do this, they will need the Satellite ID. By doing so, and because you have set them as an administrator in the previous step, the Satellite you are transferring will be linked with their account and made available in the Console. **Tip:** At this stage, the satellite is linked to both accounts, making it accessible from each. If your goal is to share the satellite, you can consider this process complete and stop here. Otherwise, continue with the next steps. #### 3\. Remove Unnecessary Access Keys The destination account — your friend or colleague, who is now the owner of the satellite — can then remove the access key(s) that should no longer be listed, specifically your own Developer ID and, if you got one, your Mission Control ID. #### 4\. Confirm and Detach Wait for confirmation that the destination account has completed all the steps and successfully taken over the satellite. Once confirmed, you can remove the satellite from your console using the "Detach Satellite" option available in the Satellite overview. --- ## How to collaborate on the same "project" Since team collaboration isn't available yet, developers often find ways to share a satellite with friends or colleagues by either adding access keys—explained in the previous section—or by sharing an Internet Identity. With the latter approach, everyone in the group logs into the Juno Console using the same identity, allowing them to access the same data effortlessly. While this method falls outside Juno's intended scope, it works similarly to adding multiple passkeys to your own Internet Identity. Here’s a simple guide to help you set it up. **Important:** Sharing the same identity also means sharing access to the same wallet linked to that identity. Be sure to follow this approach only with people you trust. #### 1\. Create a new identity Go to [id.ai](https://id.ai) and create a new identity. #### 2\. Set up Sign into the [Juno Console](https://console.juno.build) using the new identity to create a new Mission Control and set up your first or subsequent satellites. #### 3\. Plan the identity sharing Arrange a call or meeting with the person you want to share the identity with, as the upcoming steps require actions to be completed within a short time frame. #### 4\. Sign into your Internet Identity Once ready, sign again into [id.ai](https://id.ai) using the newly created identity. #### 5\. Add a new passkey Click "Add new passkey" to initiate the process of adding the other person’s device. #### 6\. Share the generated link A link (e.g.,`https://id.ai/pair#12345`) will be generated and valid for 15 minutes. Copy and send this link to the person you want to share the identity with. #### 7\. Approve the new passkey The recipient should open the link and approve the passkey by trusting their device. #### 8\. Verify with a code A six-digit code will be displayed on their screen, which they should provide to you. Enter this code on your screen to finalize the process. #### 9\. Confirm success Once the code is entered correctly, the new passkey will be added. Your collaborator can now sign into the Juno Console using the shared identity and access the same satellites. #### 10\. Optional: Rename passkeys It's recommended to rename the newly added passkey in Internet Identity to keep track of which passkey belongs to whom. **Note:** A maximum of 8 passkeys can be assigned to an identity, allowing you to share a project with up to 7 other people.