DEV Community

Sagara
Sagara

Posted on

Hosting Elementary Reports with Snowflake App Runtime Without Docker Image Management

This article is the English translation version of the original Japanese article.

https://dev.classmethod.jp/articles/snowflake-try-appruntime-with-elementary-report/

I'm Sagara.

Previously, I wrote an article about building an environment where you can view Elementary reports on the web using Snowpark Container Services.

https://dev.classmethod.jp/articles/snowpark-container-services-for-elementary-report/

After that, I also wrote an article for teams using Databricks, where I tried doing the same thing with Databricks Apps.

https://dev.classmethod.jp/articles/databricks-apps-hosting-elementary/

In the SPCS version, I had to create a Dockerfile, build a Docker image, push it to an Image Repository, create a Compute Pool, and create a service using snow spcs service create. Since an Elementary report is essentially just static files named elementary_report.html and elementary_output.json, building and pushing my own container image honestly felt a bit excessive.

Meanwhile, Snowflake App Runtime, which allows you to deploy Node.js applications, mainly Next.js applications, directly on Snowflake, has been released in Public Preview.

https://docs.snowflake.com/en/developer-guide/snowflake-app-runtime/about-snowflake-app-runtime

https://zenn.dev/snowflakejp/articles/9e5b8fa393ccd8

With Snowflake App Runtime, you can deploy an application using only snow app deploy from Snowflake CLI, without using a Dockerfile, Docker image build, or Image Repository. In this article, I tried solving the same problem — hosting Elementary reports — with Snowflake App Runtime.

:::message
Snowflake App Runtime internally runs as an Application Service on Snowpark Container Services. In the title, “without Docker” means that users do not need to manage Dockerfiles or container images themselves. Please keep this point in mind.
:::

Feature overview

Snowflake App Runtime is a feature that allows you to deploy full-stack web applications written in Node.js, especially Next.js, directly within Snowflake’s security boundary. You can also query Snowflake tables directly from your application code without going through an API layer or ETL process.

The deployment flow is as follows: initialize the project with snow app setup, then run snow app deploy to upload, build, and deploy everything at once. Once deployment is complete, an authenticated URL like the following is issued, and users logged in to Snowflake can access the application directly from their browser.

https://<id>-<org>-<account>-<region>.snowflakecomputing.app/
Enter fullscreen mode Exit fullscreen mode

Internally, it runs on Snowpark Container Services as a dedicated object type called Application Service. Since this is a different object type from traditional SPCS services, note that it does not appear in SHOW SERVICES; you need to check it with SHOW APPLICATION SERVICES.

Limitations

  • As of July 7, 2026, this is a Public Preview feature. Specifications may change before GA.
  • Trial accounts are not supported; a paid account is required.
  • Snowflake CLI 3.17 or later is required. Older versions do not have the snow app setup command.
  • During Public Preview, a managed Compute Pool is forcibly used.
  • If you do not explicitly specify the database and schema when running snow app setup, the application is deployed to a personal database by default, such as USER$<username>. Applications deployed to a personal database cannot be shared with other roles.
  • Each deployment creates a new version instead of overwriting the existing version.
  • Supported stacks are mainly Node.js/Next.js, and Python support is planned as of July 7, 2026.

Auto-suspend and cost considerations

Applications deployed with Snowflake App Runtime internally run as Application Services. Therefore, from a cost perspective, you need to be aware of the Application Service lifecycle.

Application Service has an auto-suspend setting called AUTO_SUSPEND_SECS, but the default value is 0, meaning auto-suspend is disabled. If you leave an application created for testing purposes running, compute costs may continue to be incurred unintentionally, so you should be careful.

AUTO_SUSPEND_SECS can be configured with CREATE APPLICATION SERVICE or ALTER APPLICATION SERVICE. However, as far as I checked on July 7, 2026, I could not find a way to specify it directly during deployment via snow app deploy options or snowflake.yml.

Therefore, configure it after deployment as needed, as shown below.

ALTER APPLICATION SERVICE
  SAGARA_SNOWFLAKE_APPS.PUBLIC.ELEMENTARY_REPORT_APP
SET
  AUTO_RESUME = TRUE,
  AUTO_SUSPEND_SECS = 900;
Enter fullscreen mode Exit fullscreen mode

In the example above, the Application Service is automatically suspended after 15 minutes of inactivity. The minimum non-zero value that can be specified for AUTO_SUSPEND_SECS is 300 seconds.

When an Application Service is suspended, its container stops and compute billing also stops. For test environments or internal applications that are used infrequently, it is safer to set AUTO_SUSPEND_SECS after running snow app deploy.

For reference, the Consumption Table listed the App Runtime unit price as shown below as of July 7, 2026.

2026-07-07_22h46_32

Prerequisites

This validation assumes that the following have already been completed.

  • Snowflake: A paid account, not a Trial account. The account must be able to use Snowflake App Runtime.
  • Feature status: Public Preview as of July 7, 2026.
  • Snowflake CLI: Version 3.17 or later is installed and can connect to the target account.
  • Node.js: Installed for local testing.
  • Elementary report files: elementary_report.html and elementary_output.json have already been generated.

The Snowflake object names used in this article are standardized as follows.

Object Name
Database SAGARA_SNOWFLAKE_APPS
Schema PUBLIC
Warehouse SAGARA_SNOWFLAKE_APPS_QUERY_WH
App name elementary_report_app
Application Service ELEMENTARY_REPORT_APP

Preparation

Check Snowflake CLI version and connection

First, confirm that the Snowflake CLI version is 3.17 or later.

snow --version
Enter fullscreen mode Exit fullscreen mode

Also check whether the snow app setup command exists. If you are using an older version, please upgrade it.

snow app setup --help
Enter fullscreen mode Exit fullscreen mode

Next, check the connection to the target account.

snow connection test
Enter fullscreen mode Exit fullscreen mode

If you use multiple connections, specify the connection name. Add --connection <connection_name> to the following commands as needed.

snow connection test --connection <connection_name>
Enter fullscreen mode Exit fullscreen mode

If the connection information is displayed correctly, you are good to go.

Also check the Node.js version.

node --version
Enter fullscreen mode Exit fullscreen mode

Check Elementary report files

This article assumes that the Elementary report has already been generated at the root of your dbt project.

dbt_project/
├── dbt_project.yml
├── models/
├── edr_target/
│   ├── elementary_report.html
│   └── elementary_output.json
Enter fullscreen mode Exit fullscreen mode

What I tried

1. Create a directory for App Runtime

Create a local directory for App Runtime and copy the Elementary report files.

mkdir -p elementary-report-app/public
Enter fullscreen mode Exit fullscreen mode

Rename elementary_report.html to index.html when copying it. This allows the Elementary report to be displayed simply by accessing the root URL of the application.

cp edr_target/elementary_report.html elementary-report-app/public/index.html
cp edr_target/elementary_output.json elementary-report-app/public/elementary_output.json

cd elementary-report-app
Enter fullscreen mode Exit fullscreen mode

The final directory structure is as follows. We will create each file from here.

elementary-report-app/
├── app.yml
├── package.json
├── server.mjs
├── snowflake.yml        # Generated by snow app setup
└── public/
    ├── index.html
    └── elementary_output.json
Enter fullscreen mode Exit fullscreen mode

2. Create server.mjs

Create server.mjs, which starts an HTTP server on Snowflake App Runtime. In the SPCS version, I served static files using an Nginx container, but this time I will use a minimal HTTP server built with Node.js.

Save the following content as elementary-report-app/server.mjs.

// server.mjs
import http from "node:http";
import { readFile, stat, readdir } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Use the App Runtime execution package root as the document root
const documentRoot = __dirname;

const port = Number(process.env.PORT || process.env.SERVER_PORT || 8080);
const host = "0.0.0.0";

const mimeTypes = {
  ".html": "text/html; charset=utf-8",
  ".json": "application/json; charset=utf-8",
  ".js": "text/javascript; charset=utf-8",
  ".css": "text/css; charset=utf-8",
  ".svg": "image/svg+xml",
  ".png": "image/png",
  ".jpg": "image/jpeg",
  ".jpeg": "image/jpeg",
  ".ico": "image/x-icon",
  ".map": "application/json; charset=utf-8",
  ".txt": "text/plain; charset=utf-8",
};

async function listFilesRecursive(dir, baseDir = dir) {
  const entries = await readdir(dir, { withFileTypes: true });
  const files = [];

  for (const entry of entries) {
    const fullPath = path.join(dir, entry.name);
    const relativePath = path.relative(baseDir, fullPath);

    if (entry.isDirectory()) {
      const childFiles = await listFilesRecursive(fullPath, baseDir);
      files.push(...childFiles);
    } else {
      files.push(relativePath);
    }
  }

  return files;
}

function safeResolve(urlPath) {
  const decodedPath = decodeURIComponent(urlPath.split("?")[0]);

  // Return index.html for root access
  const normalizedPath = decodedPath === "/" ? "/index.html" : decodedPath;

  const filePath = path.normalize(path.join(documentRoot, normalizedPath));

  // Prevent directory traversal
  if (!filePath.startsWith(documentRoot)) {
    return null;
  }

  return filePath;
}

const server = http.createServer(async (req, res) => {
  try {
    if (!req.url) {
      res.writeHead(400, {
        "content-type": "text/plain; charset=utf-8",
      });
      res.end("Bad Request");
      return;
    }

    console.log(JSON.stringify({
      message: "request",
      url: req.url,
      cwd: process.cwd(),
      dirname: __dirname,
      documentRoot,
    }));

    if (req.url === "/healthz") {
      res.writeHead(200, {
        "content-type": "text/plain; charset=utf-8",
      });
      res.end("ok");
      return;
    }

    // For debugging: check the list of files available in the runtime environment
    if (req.url === "/__debug/files") {
      const files = await listFilesRecursive(documentRoot);

      res.writeHead(200, {
        "content-type": "application/json; charset=utf-8",
      });
      res.end(JSON.stringify({
        cwd: process.cwd(),
        dirname: __dirname,
        documentRoot,
        files,
      }, null, 2));
      return;
    }

    const filePath = safeResolve(req.url);

    console.log(JSON.stringify({
      message: "resolved file path",
      url: req.url,
      filePath,
    }));

    if (!filePath) {
      res.writeHead(403, {
        "content-type": "text/plain; charset=utf-8",
      });
      res.end("Forbidden");
      return;
    }

    const fileStat = await stat(filePath);

    if (!fileStat.isFile()) {
      res.writeHead(404, {
        "content-type": "text/plain; charset=utf-8",
      });
      res.end("Not Found");
      return;
    }

    const body = await readFile(filePath);
    const ext = path.extname(filePath).toLowerCase();
    const contentType = mimeTypes[ext] || "application/octet-stream";

    res.writeHead(200, {
      "content-type": contentType,
      "cache-control": "no-store",
    });
    res.end(body);
  } catch (err) {
    console.error(JSON.stringify({
      message: "request failed",
      url: req.url,
      error: err instanceof Error ? err.message : String(err),
    }));

    res.writeHead(404, {
      "content-type": "text/plain; charset=utf-8",
    });
    res.end("Not Found");
  }
});

server.listen(port, host, () => {
  console.log(JSON.stringify({
    message: "Elementary report server started",
    url: `http://${host}:${port}`,
    cwd: process.cwd(),
    dirname: __dirname,
    documentRoot,
  }));
});
Enter fullscreen mode Exit fullscreen mode

The key points are as follows.

  • It reads the port number from the PORT or SERVER_PORT environment variable, and defaults to 8080 if neither is set.
  • It listens on 0.0.0.0 so that it can receive requests from the Application Service.
  • It provides a /healthz endpoint that can be used for health checks.
  • It includes directory traversal protection using path.normalize and startsWith.
  • It does not depend on any external npm packages and uses only standard Node.js modules.

3. Create package.json

Next, create package.json.

{
  "name": "elementary-report-app",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=22"
  },
  "scripts": {
    "start": "node server.mjs"
  }
}
Enter fullscreen mode Exit fullscreen mode

Since this configuration does not use any external npm packages, npm install and node_modules are basically unnecessary.

4. Create app.yml

app.yml is the file that defines the build, execution, and packaging behavior for App Runtime.

run:
  command: [node, server.mjs]

artifacts:
  - src: "server.mjs"
    dest: "."
  - src: "package.json"
    dest: "."
  - src: "public/index.html"
    dest: "."
  - src: "public/elementary_output.json"
    dest: "."

profile:
  label: "Elementary Report"
  description: "Static hosting for Elementary report on Snowflake App Runtime"
Enter fullscreen mode Exit fullscreen mode

Here, the following are defined.

  • run.command: The command executed when the application starts.
  • artifacts: Files to include in the deployment target. This includes server.mjs, package.json, and the Elementary report files under public/.
  • profile: The application label and description.

Be careful that if the destination path of the files under public/ and the path referenced by server.mjs do not match, the Elementary report will return 404 after deployment. Details are described later in the “Issue I ran into” section.

5. Test locally

Before deploying to Snowflake, verify locally that server.mjs works as expected.

npm start
Enter fullscreen mode Exit fullscreen mode

In another terminal, run a health check.

curl http://localhost:8080/healthz
Enter fullscreen mode Exit fullscreen mode

If the following is returned, it is OK.

ok
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:8080 in your browser and confirm that the Elementary report screen is displayed.

2026-07-07_21h54_42

Once confirmed, stop the server with Ctrl + C.

6. Create Snowflake objects

Create a Database and Warehouse for testing. Use PUBLIC as the Schema.

USE ROLE ACCOUNTADMIN;

CREATE DATABASE IF NOT EXISTS SAGARA_SNOWFLAKE_APPS;

CREATE WAREHOUSE IF NOT EXISTS SAGARA_SNOWFLAKE_APPS_QUERY_WH
  WAREHOUSE_SIZE = XSMALL
  AUTO_SUSPEND = 60
  AUTO_RESUME = TRUE
  INITIALLY_SUSPENDED = TRUE;
Enter fullscreen mode Exit fullscreen mode

Normally, the PUBLIC schema is also created when the Database is created, but if you want to create it explicitly, run the following as well.

CREATE SCHEMA IF NOT EXISTS SAGARA_SNOWFLAKE_APPS.PUBLIC;
Enter fullscreen mode Exit fullscreen mode

Grant privileges to the role that deploys the application as needed. For example, if deploying with the SYSADMIN role, run the following.

USE ROLE ACCOUNTADMIN;

GRANT USAGE ON WAREHOUSE SAGARA_SNOWFLAKE_APPS_QUERY_WH TO ROLE SYSADMIN;

GRANT USAGE ON DATABASE SAGARA_SNOWFLAKE_APPS TO ROLE SYSADMIN;
GRANT USAGE ON SCHEMA SAGARA_SNOWFLAKE_APPS.PUBLIC TO ROLE SYSADMIN;

GRANT CREATE APPLICATION SERVICE ON SCHEMA SAGARA_SNOWFLAKE_APPS.PUBLIC TO ROLE SYSADMIN;
GRANT CREATE STAGE ON SCHEMA SAGARA_SNOWFLAKE_APPS.PUBLIC TO ROLE SYSADMIN;
Enter fullscreen mode Exit fullscreen mode

7. Set up Snowflake App Runtime

Create the configuration for App Runtime. By explicitly specifying the deployment destination, you can avoid deploying to a personal database.

snow app setup \
  --app-name elementary_report_app \
  --database SAGARA_SNOWFLAKE_APPS \
  --schema PUBLIC \
  --warehouse SAGARA_SNOWFLAKE_APPS_QUERY_WH
Enter fullscreen mode Exit fullscreen mode

If you use multiple connections, specify the connection name.

snow app setup \
  --connection <connection_name> \
  --app-name elementary_report_app \
  --database SAGARA_SNOWFLAKE_APPS \
  --schema PUBLIC \
  --warehouse SAGARA_SNOWFLAKE_APPS_QUERY_WH
Enter fullscreen mode Exit fullscreen mode

After execution, snowflake.yml is generated automatically. The following is the content of the file generated when I ran the command.

2026-07-07_21h59_05

definition_version: "2"

entities:
  elementary_report_app:
    type: snowflake-app
    identifier:
      name: ELEMENTARY_REPORT_APP
      database: SAGARA_SNOWFLAKE_APPS
      schema: PUBLIC
    artifacts:
      - src: ./*
        dest: ./
        ignore:
          - node_modules
          - .env*
          - __pycache__
          - "*.pyc"
          - .next
          - .git
          - snowflake.log

    query_warehouse: SAGARA_SNOWFLAKE_APPS_QUERY_WH
    code_stage: ELEMENTARY_REPORT_APP_CODE
Enter fullscreen mode Exit fullscreen mode

If database and schema are set to a personal database, such as USER$<username>, the application cannot be shared with your team. Explicitly specify the --database and --schema options and rerun snow app setup.

8. Deploy

Run snow app deploy to upload, build, and deploy to Snowflake all at once.

snow app deploy
Enter fullscreen mode Exit fullscreen mode

If you want to explicitly specify the connection name, run the following.

snow app deploy --connection <connection_name>
Enter fullscreen mode Exit fullscreen mode

Even if the log appears to be stuck at the same point, wait until a message like App ready at https://... is displayed.

2026-07-07_22h02_33

After a few minutes, if the following is displayed, the deployment has succeeded.

2026-07-07_22h04_15

9. Open the app and display the report

Once deployment is complete, open the application in your browser with snow app open.

snow app open
Enter fullscreen mode Exit fullscreen mode

If you want to explicitly specify the connection name, run the following.

snow app open --connection <connection_name>
Enter fullscreen mode Exit fullscreen mode

If you only want to display the URL, add --print-only. Since I tested this on Ubuntu 24.04 LTS running on WSL2, I ran the following command.

snow app open --print-only
Enter fullscreen mode Exit fullscreen mode

2026-07-07_22h05_59

Paste this URL into your browser, authenticate with Snowflake, and if the Elementary report is displayed in the browser, it is successful.

2026-07-07_22h07_08

2026-07-07_22h29_38

10. Share with other roles

If you want to share the application with team members, grant the USAGE privilege to the target role. In this example, I share it with the ANALYST role.

USE ROLE ACCOUNTADMIN;

GRANT USAGE ON DATABASE SAGARA_SNOWFLAKE_APPS TO ROLE ANALYST;

GRANT USAGE ON SCHEMA SAGARA_SNOWFLAKE_APPS.PUBLIC TO ROLE ANALYST;

GRANT USAGE ON APPLICATION SERVICE
  SAGARA_SNOWFLAKE_APPS.PUBLIC.ELEMENTARY_REPORT_APP
  TO ROLE ANALYST;
Enter fullscreen mode Exit fullscreen mode

This allows users with the ANALYST role to access the App Runtime URL through Snowflake authentication.

11. Check the Application Service

The created Application Service can be checked with SHOW APPLICATION SERVICES, not SHOW SERVICES.

USE DATABASE SAGARA_SNOWFLAKE_APPS;
USE SCHEMA PUBLIC;

SHOW APPLICATION SERVICES;
Enter fullscreen mode Exit fullscreen mode

If you want to filter only the target Application Service, run the following.

SHOW APPLICATION SERVICES LIKE 'ELEMENTARY_REPORT_APP';
Enter fullscreen mode Exit fullscreen mode

If ELEMENTARY_REPORT_APP is displayed, it is OK.

2026-07-07_22h12_46

12. Flow when updating the report

After regenerating the Elementary report, replace the files under public/ and redeploy.

If you are working from the root of the dbt project, run the following.

cp edr_target/elementary_report.html elementary-report-app/public/index.html
cp edr_target/elementary_output.json elementary-report-app/public/elementary_output.json

cd elementary-report-app

snow app deploy
Enter fullscreen mode Exit fullscreen mode

If you are already in the elementary-report-app directory, run the following.

cp ../edr_target/elementary_report.html public/index.html
cp ../edr_target/elementary_output.json public/elementary_output.json

snow app deploy
Enter fullscreen mode Exit fullscreen mode

Internally, a new version is created, and the Application Service reference is switched to the new version. As a result, you can access the latest Elementary report using the same URL. If these commands are incorporated into a CI/CD pipeline or executed after dbt runs, report updates could also be automated.

13. Stop the deployed app

Finally, I will also describe how to stop the App Runtime application after testing.

An application deployed with Snowflake App Runtime runs as an Application Service.

If it is no longer needed, you can delete the Application Service with snow app teardown.

snow app teardown --connection <connection_name>
Enter fullscreen mode Exit fullscreen mode

If you want to skip the confirmation prompt, add --force.

snow app teardown --connection <connection_name> --force
Enter fullscreen mode Exit fullscreen mode

This command deletes the target Application Service based on the current project definition, namely snowflake.yml inside the elementary-report-app directory.

Therefore, you should basically run it in the directory where snowflake.yml exists.

cd elementary-report-app

snow app teardown --connection <connection_name>
Enter fullscreen mode Exit fullscreen mode

When you actually run it, it is displayed as shown below.

2026-07-07_22h53_29

After deletion, you can confirm that the Application Service no longer exists with the following SQL.

USE DATABASE SAGARA_SNOWFLAKE_APPS;
USE SCHEMA PUBLIC;

SHOW APPLICATION SERVICES LIKE 'ELEMENTARY_REPORT_APP';
Enter fullscreen mode Exit fullscreen mode

If ELEMENTARY_REPORT_APP is not displayed, the deletion is complete.

Note that snow app teardown deletes the Application Service and related files on the code stage, but it does not delete the Database or Warehouse created in this article.

If the Snowflake objects created for testing are also no longer needed, delete them separately as follows.

USE ROLE ACCOUNTADMIN;

DROP WAREHOUSE IF EXISTS SAGARA_SNOWFLAKE_APPS_QUERY_WH;
DROP DATABASE IF EXISTS SAGARA_SNOWFLAKE_APPS;
Enter fullscreen mode Exit fullscreen mode

If you want to start the stopped application again, simply deploy it again from the same project directory.

snow app deploy --connection <connection_name>
Enter fullscreen mode Exit fullscreen mode

Issue I ran into: Not Found after opening the URL post-deployment

This time, I encountered an issue where snow app deploy completed successfully and an App Runtime URL was issued, but opening the URL in the browser showed Not Found.

In the deployment log, public/index.html and public/elementary_output.json were uploaded to the stage as follows.

Uploaded public/elementary_output.json -> ...
Uploaded public/index.html -> ...
Enter fullscreen mode Exit fullscreen mode

At first, I thought, “The files should have been uploaded, so why?” But the cause was that after being uploaded to the stage, the files did not exist at the path referenced by the Node.js server inside the App Runtime execution package.

Initially, I specified the following in app.yml.

artifacts:
  - src: "public/**"
    dest: "public"
Enter fullscreen mode Exit fullscreen mode

On the other hand, server.mjs was implemented to reference public/index.html.

However, the files were not arranged as expected in the runtime environment, and as a result, index.html could not be found and Not Found was returned.

In the end, instead of preserving the public/ directory inside the execution package, I changed the configuration to place the required static files at the package root.

artifacts:
  - src: "server.mjs"
    dest: "."
  - src: "package.json"
    dest: "."
  - src: "public/index.html"
    dest: "."
  - src: "public/elementary_output.json"
    dest: "."
Enter fullscreen mode Exit fullscreen mode

I also changed server.mjs to treat the execution package root as the document root.

const documentRoot = __dirname;
Enter fullscreen mode Exit fullscreen mode

As a result, the files were arranged as follows on App Runtime, and index.html could be returned correctly from the root URL.

/
├── server.mjs
├── package.json
├── index.html
└── elementary_output.json
Enter fullscreen mode Exit fullscreen mode

If snow app deploy succeeds but the screen shows Not Found, as in this case, it may not be an endpoint creation issue. Instead, the file placement in the App Runtime execution environment and the reference path in the application may be misaligned.

It was helpful to prepare /healthz and a simple debug endpoint that returns the list of files in the runtime environment, as it made it easier to identify the cause.

Comparison with the SPCS version and Databricks Apps version

Compared with the two configurations I tried previously, the differences are as follows.

Item SPCS version Databricks Apps version App Runtime version, this article
Static file serving Nginx container Python http.server Minimal HTTP server with Node.js
Dockerfile Required Not required Not required
Docker build Required Not required Not required
Image Repository Required Not required Not required
docker push Required Not required Not required
Compute Pool Created manually Select Compute Size for Databricks Apps Managed Pool handled by App Runtime
Sharing method Grant to SERVICE ROLE Grant CAN USE permission on Databricks Apps side Grant USAGE to Application Service

The following tasks required in the SPCS version are no longer necessary in the App Runtime version.

  • Creating a Dockerfile
  • Configuring Nginx
  • Building a Docker image
  • Creating a Snowflake Image Repository
  • docker login / docker push
  • Creating a Compute Pool
  • Creating a service spec YAML
  • snow spcs service create / snow spcs service list-endpoints

Instead, only the following files and commands are needed. Once the application files are ready, you can immediately deploy the app and share it with users in your Snowflake account. This is a major strength of Snowflake App Runtime!

  • server.mjs
  • package.json
  • app.yml
  • snowflake.yml, generated by snow app setup
  • snow app setup / snow app deploy / snow app open

Conclusion

I tried hosting an Elementary report without Docker by using Snowflake App Runtime.

Compared with SPCS, Snowflake App Runtime removes the entire burden of container image management. For lightweight internal web publishing use cases like Elementary reports, Snowflake App Runtime looks like a very easy-to-use option. Since the specifications may change toward GA, I will continue to keep an eye on it!

Top comments (0)