Deploying an Analog App
Analog is a full-stack meta-framework for Angular that combines file-based routing, server-side rendering (SSR), static-site generation, and API routes on top of Vite. Built on modern Angular and featuring seamless TypeScript support, Analog enables developers to build fast, SEO-friendly applications with an exceptional developer experience.
This comprehensive guide walks through deploying an Analog app to Klutch.sh using either Nixpacks (automatic zero-configuration deployment) or a Dockerfile (manual container control). You’ll learn how to create and structure an Analog project, add sample code and API routes, configure environment variables, implement security best practices, set up monitoring, and troubleshoot common deployment issues. By the end of this guide, you’ll have a production-ready Analog application running on Klutch.sh’s global infrastructure.
Prerequisites
- Node.js & npm (version 18+) – Download Node.js
- Git installed locally and a GitHub account (Klutch.sh uses GitHub as the only git source)
- Klutch.sh account with access to the dashboard at klutch.sh/app
- Basic understanding of Analog, Angular, TypeScript, and the Node.js ecosystem
Getting Started: Create an Analog App
You can create a new Analog app using the official scaffolding tool or manually configure an existing Angular project. Below is the recommended approach for a fresh Analog project.
1. Scaffold a New Analog Project
In an empty directory, use the official Analog starter:
npm init @analogjs/app@latest my-analog-appcd my-analog-appnpm installThis command creates a fully configured Analog project with pre-set scripts, routing, and Vite configuration.
2. Project Structure
A typical Analog project structure looks like:
my-analog-app/├── src/│ ├── app/│ │ ├── pages/│ │ │ ├── index.page.ts│ │ │ ├── about.page.ts│ │ │ └── ...│ │ ├── api/│ │ │ ├── articles/│ │ │ │ ├── [id].ts│ │ │ │ └── index.ts│ │ │ └── ...│ │ └── ...│ ├── main.ts│ ├── main.server.ts│ └── styles.css├── package.json├── vite.config.ts├── Dockerfile└── README.md3. Run the Development Server
Start the Analog development server:
npm run devNavigate to http://localhost:5173 in your browser. Hot module replacement (HMR) is enabled by default.
4. Sample Page Component
Create a simple home page to verify local development:
import { Component } from '@angular/core';import { CommonModule } from '@angular/common';
@Component({ selector: 'app-home-page', standalone: true, imports: [CommonModule], template: ` <main class="home-container"> <h1>Welcome to Analog</h1> <p>This Analog app is running on Klutch.sh.</p> <section> <h2>Features</h2> <ul> <li>File-based routing with dynamic routes</li> <li>Server-side rendering (SSR) for SEO</li> <li>API routes for backend functionality</li> <li>Full TypeScript support</li> </ul> </section> </main> `, styles: [ ` .home-container { max-width: 800px; margin: 0 auto; padding: 2rem; font-family: system-ui, -apple-system, sans-serif; } `, ],})export default class HomePage {}5. Sample API Route
Create an API endpoint that returns JSON data:
import { defineEventHandler, readBody } from 'h3';
interface Article { id: number; title: string; content: string;}
const articles: Article[] = [ { id: 1, title: 'Getting Started with Analog', content: 'Learn the basics of Analog framework.', }, { id: 2, title: 'SSR with Analog', content: 'Build server-rendered Angular applications.', },];
export default defineEventHandler(async (event) => { if (event.node.req.method === 'GET') { return articles; }
if (event.node.req.method === 'POST') { const body = await readBody(event); const newArticle: Article = { id: articles.length + 1, ...body, }; articles.push(newArticle); return newArticle; }
return { error: 'Method not allowed' };});6. Dynamic API Route
Create a dynamic route for fetching a single article:
import { defineEventHandler } from 'h3';
interface Article { id: number; title: string; content: string;}
const articles: Article[] = [ { id: 1, title: 'Getting Started with Analog', content: 'Learn the basics of Analog framework.', }, { id: 2, title: 'SSR with Analog', content: 'Build server-rendered Angular applications.', },];
export default defineEventHandler((event) => { const id = parseInt(event.context.params?.id as string, 10); const article = articles.find((a) => a.id === id);
if (!article) { event.node.res.statusCode = 404; return { error: 'Article not found' }; }
return article;});7. Production Build Scripts
Ensure your package.json includes the necessary production scripts:
{ "scripts": { "dev": "analog dev", "build": "analog build", "start": "analog start", "preview": "vite preview", "type-check": "tsc --noEmit" }, "dependencies": { "@analogjs/core": "^1.0.0", "@angular/animations": "^17.0.0", "@angular/common": "^17.0.0", "@angular/compiler": "^17.0.0", "@angular/core": "^17.0.0", "@angular/platform-browser": "^17.0.0", "@angular/platform-browser-dynamic": "^17.0.0", "express": "^4.18.0", "vite": "^5.0.0", "zone.js": "^0.14.0" }, "devDependencies": { "@angular/compiler-cli": "^17.0.0", "@types/node": "^20.0.0", "typescript": "^5.2.0" }}Local Production Test
Before deploying, test the production build locally:
npm run buildnpm run startVisit http://localhost:3000 to verify that your app renders correctly in production mode.
Deploying with Nixpacks
Nixpacks automatically detects your Node.js application and configures build and runtime environments without requiring a Dockerfile. This is the simplest deployment method for Analog apps.
Prerequisites for Nixpacks Deployment
- Your Analog project pushed to a GitHub repository
- Valid
package.jsonwithbuildandstartscripts - No
Dockerfilein the repository root (if one exists, Klutch.sh will use Docker instead)
Steps to Deploy with Nixpacks
-
Push Your Analog Project to GitHub
Initialize and push your project to GitHub if you haven’t already:
Terminal window git initgit add .git commit -m "Initial Analog app"git branch -M maingit remote add origin git@github.com:YOUR_USERNAME/YOUR_REPO.gitgit push -u origin main -
Log In to Klutch.sh Dashboard
Go to klutch.sh/app and sign in with your GitHub account.
-
Create a Project
Navigate to the Projects section and create a new project for your Analog app.
-
Create an App
Click “Create App” and select your GitHub repository.
-
Select the Branch
Choose the branch you want to deploy (typically
main). -
Configure Traffic Type
Select HTTP as the traffic type for Analog (a web framework serving HTML/JSON).
-
Set the Internal Port
Set the internal port to
3000– this is the port where your Analog server listens internally. -
Add Environment Variables (Optional)
Add any environment variables your Analog app requires:
NODE_ENV=productionAPI_URL=https://api.example.comLOG_LEVEL=infoIf you need to customize the Nixpacks build or start command:
BUILD_COMMAND: Override the default build command (e.g.,npm run build && npm run build:server)START_COMMAND: Override the default start command (e.g.,node dist/server.js)
-
Configure Compute Resources
Select your region, compute size, and number of instances based on expected traffic.
-
Deploy
Click “Create” to start the deployment. Nixpacks will automatically build and deploy your Analog app. Your app will be available at a URL like
https://example-app.klutch.sh.
Deploying with Docker
For more control over your deployment environment, you can use a Dockerfile. Klutch.sh automatically detects a Dockerfile in your repository root and uses it for deployment.
Creating a Dockerfile for Analog
Create a Dockerfile in the root of your Analog project:
# === Build stage ===FROM node:20-alpine AS builder
WORKDIR /app
# Install dependenciesCOPY package*.json ./RUN npm install
# Copy the rest of the source codeCOPY . .
# Build the Analog app for productionRUN npm run build
# === Runtime stage ===FROM node:20-alpine AS runtime
WORKDIR /app
# Copy package filesCOPY package*.json ./
# Install production dependencies onlyRUN npm install --omit=dev
# Copy built assets and compiled code from builderCOPY --from=builder /app/dist ./dist
# Set the port for Analog to listen onENV PORT=3000EXPOSE 3000
# Start the Analog server in production modeCMD ["npm", "run", "start"]Dockerfile Notes
- Builder stage: Installs all dependencies (including dev) and builds the Analog app.
- Runtime stage: Contains only production dependencies and the compiled app, resulting in a smaller, more secure image.
- Port: The
PORTenvironment variable is set to3000, which is the recommended internal port for Analog. - Multi-stage build: Reduces final image size by excluding build tools and dev dependencies.
Steps to Deploy with Docker
-
Create a Dockerfile
Add the Dockerfile (shown above) to the root of your Analog repository.
-
Test Locally (Optional)
Build and test the Docker image locally:
Terminal window docker build -t analog-app:latest .docker run -p 3000:3000 analog-app:latestVisit http://localhost:3000 to verify.
-
Push to GitHub
Commit and push the Dockerfile and your code:
Terminal window git add Dockerfilegit commit -m "Add Dockerfile for production deployment"git push origin main -
Create an App in Klutch.sh
Go to klutch.sh/app, navigate to “Create App”, and select your repository.
-
Configure the App
- Traffic Type: Select HTTP
- Internal Port: Set to
3000 - Environment Variables: Add any required runtime variables
-
Deploy
Klutch.sh automatically detects the Dockerfile and uses it to build and deploy your app. Your app will be available at
https://example-app.klutch.sh.
Database Configuration
Many Analog applications require a database for persisting data. Klutch.sh supports integration with PostgreSQL and MySQL.
Environment Variables for Database Connection
Set these environment variables in the Klutch.sh dashboard:
DATABASE_URL=postgresql://user:password@host:5432/dbname# orDATABASE_URL=mysql://user:password@host:3306/dbnameConnecting to a Database Service
If you’re running a separate database service on Klutch.sh:
- Deploy a PostgreSQL or MySQL service on Klutch.sh.
- In your Analog app, retrieve the database connection details from Klutch.sh (usually provided as an environment variable).
- Update your connection configuration in your Analog app to use the provided
DATABASE_URL.
Sample Database Integration
Create a service to handle database operations:
import { Injectable } from '@angular/core';
interface Article { id: number; title: string; content: string; author: string; created_at: string;}
@Injectable({ providedIn: 'root',})export class ArticleService { private dbUrl = process.env['DATABASE_URL'];
constructor() { console.log('Database URL configured:', this.dbUrl ? 'Yes' : 'No'); }
async getArticles(): Promise<Article[]> { // Example: Use database client (e.g., node-postgres, mysql2) // This is a placeholder for your actual database logic const articles: Article[] = [ { id: 1, title: 'Analog on Klutch.sh', content: 'Deploy full-stack Angular apps with ease.', author: 'Jane Doe', created_at: new Date().toISOString(), }, ]; return articles; }
async getArticleById(id: number): Promise<Article | null> { const articles = await this.getArticles(); return articles.find((a) => a.id === id) || null; }}Environment Variables
Define all environment variables in the Klutch.sh dashboard. Here’s a recommended set for production:
NODE_ENV=productionPORT=3000LOG_LEVEL=infoAPI_URL=https://api.example.comDATABASE_URL=postgresql://user:password@host:5432/dbnameREDIS_URL=redis://host:6379SESSION_SECRET=your-secure-random-secretDEBUG=falseRATE_LIMIT_ENABLED=trueAccessing Environment Variables in Analog
Access environment variables in both server and client code:
// Server-side (API routes)const nodeEnv = process.env['NODE_ENV'];const databaseUrl = process.env['DATABASE_URL'];
// Client-side (with caution – only public variables)declare const process: any;const apiUrl = import.meta.env['VITE_API_URL'];Persistent Storage
If your Analog app needs to store uploaded files or other persistent data, attach a volume in Klutch.sh.
Adding a Persistent Volume
- In the Klutch.sh dashboard, go to your app’s Volumes section.
- Click Add Volume.
- Set the mount path (e.g.,
/data,/uploads, or/var/www/data). - Set the size (e.g.,
1 GiB,10 GiB). - Save and redeploy your app.
Using Persistent Storage in Analog
Update your API routes to write files to the mounted directory:
import { defineEventHandler, readMultipartFormData } from 'h3';import { writeFile } from 'fs/promises';import { join } from 'path';
export default defineEventHandler(async (event) => { const formData = await readMultipartFormData(event); const file = formData?.find((f) => f.name === 'file');
if (!file) { return { error: 'No file provided' }; }
const uploadsDir = '/data/uploads'; // Mount path const fileName = `${Date.now()}-${file.filename}`; const filePath = join(uploadsDir, fileName);
await writeFile(filePath, file.data);
return { success: true, fileName, path: `/uploads/${fileName}`, };});Caching with Redis
Improve performance by caching frequently accessed data with Redis.
Environment Configuration
Set the Redis connection URL in the Klutch.sh dashboard:
REDIS_URL=redis://host:6379Redis Integration Example
Create a caching utility:
import * as redis from 'redis';
let redisClient: redis.RedisClientType;
export async function initRedis() { const redisUrl = process.env['REDIS_URL'] || 'redis://localhost:6379'; redisClient = redis.createClient({ url: redisUrl }); redisClient.on('error', (err) => console.error('Redis error:', err)); await redisClient.connect();}
export async function getCached<T>(key: string): Promise<T | null> { const cached = await redisClient.get(key); return cached ? JSON.parse(cached) : null;}
export async function setCached<T>(key: string, value: T, ttl = 3600) { await redisClient.setEx(key, ttl, JSON.stringify(value));}
export async function deleteCached(key: string) { await redisClient.del(key);}Use caching in your API routes:
import { defineEventHandler } from 'h3';import { getCached, setCached } from '../../utils/cache';
const articles = [ { id: 1, title: 'Getting Started', content: 'Learn Analog...', },];
export default defineEventHandler(async (event) => { if (event.node.req.method === 'GET') { const cached = await getCached('articles'); if (cached) { return cached; }
const data = articles; await setCached('articles', data, 3600); // Cache for 1 hour return data; }
return [];});Security Best Practices
1. HTTPS/SSL Enforcement
Klutch.sh automatically provides HTTPS for all deployed apps. Ensure your app redirects HTTP to HTTPS:
import { defineEventHandler } from 'h3';
export default defineEventHandler((event) => { const protocol = event.node.req.headers['x-forwarded-proto']; if (protocol === 'http' && process.env['NODE_ENV'] === 'production') { const url = new URL(event.node.req.url || '/', `https://${event.node.req.headers.host}`); event.node.res.writeHead(301, { Location: url.toString() }); event.node.res.end(); }});2. CORS Configuration
Restrict cross-origin requests to trusted domains:
import { defineEventHandler } from 'h3';
export default defineEventHandler((event) => { const origin = event.node.req.headers['origin'] || ''; const allowedOrigins = [ 'https://example-app.klutch.sh', 'https://example.com', ];
if (allowedOrigins.includes(origin)) { event.node.res.setHeader('Access-Control-Allow-Origin', origin); event.node.res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); event.node.res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); }
if (event.node.req.method === 'OPTIONS') { event.node.res.writeHead(200); event.node.res.end(); }});3. Environment Secrets
Never commit sensitive information. Use Klutch.sh’s environment variables for:
- Database credentials
- API keys
- Session secrets
- JWT signing keys
DATABASE_PASSWORD=your-secure-passwordAPI_KEY=your-api-keySESSION_SECRET=generate-with-crypto.randomBytes(32)JWT_SECRET=your-jwt-secret4. Input Validation
Validate all user inputs in API routes:
import { defineEventHandler, readBody } from 'h3';
export default defineEventHandler(async (event) => { if (event.node.req.method === 'POST') { const body = await readBody(event);
// Validate required fields if (!body.title || !body.content || !body.author) { event.node.res.statusCode = 400; return { error: 'Missing required fields' }; }
// Validate field lengths if (body.title.length > 255 || body.content.length > 10000) { event.node.res.statusCode = 400; return { error: 'Field length exceeded' }; }
// Sanitize and process return { success: true, article: body }; }});5. Authentication & Authorization
Implement JWT-based authentication:
import * as jwt from 'jsonwebtoken';
const SECRET = process.env['JWT_SECRET'] || 'dev-secret';
export function generateToken(userId: string) { return jwt.sign({ userId }, SECRET, { expiresIn: '24h' });}
export function verifyToken(token: string) { try { return jwt.verify(token, SECRET); } catch { return null; }}Use authentication middleware in protected routes:
import { defineEventHandler } from 'h3';import { verifyToken } from '../utils/auth';
export default defineEventHandler((event) => { const authHeader = event.node.req.headers['authorization']; const token = authHeader?.replace('Bearer ', '');
if (!token || !verifyToken(token)) { event.node.res.statusCode = 401; return { error: 'Unauthorized' }; }
return { message: 'Access granted', data: 'Protected content' };});6. Rate Limiting
Prevent abuse by implementing rate limiting:
import { defineEventHandler } from 'h3';
const requests: { [key: string]: number[] } = {};const LIMIT = 100; // requests per minuteconst WINDOW = 60 * 1000; // 1 minute
export default defineEventHandler((event) => { const ip = event.node.req.headers['x-forwarded-for'] as string || 'unknown'; const now = Date.now();
if (!requests[ip]) { requests[ip] = []; }
// Remove old requests outside the window requests[ip] = requests[ip].filter((time) => now - time < WINDOW);
if (requests[ip].length >= LIMIT) { event.node.res.statusCode = 429; return { error: 'Rate limit exceeded' }; }
requests[ip].push(now);});7. Structured Logging
Log security events for monitoring:
export function logSecurityEvent(event: string, details: Record<string, any>) { const timestamp = new Date().toISOString(); console.log( JSON.stringify({ timestamp, event, level: 'security', ...details, }) );}Monitoring and Logging
Health Check Endpoint
Implement a health check endpoint for monitoring:
import { defineEventHandler } from 'h3';
export default defineEventHandler((event) => { const uptime = process.uptime(); const memoryUsage = process.memoryUsage();
return { status: 'healthy', uptime, timestamp: new Date().toISOString(), memory: { rss: Math.round(memoryUsage.rss / 1024 / 1024) + ' MB', heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024) + ' MB', heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024) + ' MB', }, };});Structured Logging
Implement structured logging for better observability:
export function logRequest(method: string, path: string, status: number, duration: number) { console.log( JSON.stringify({ timestamp: new Date().toISOString(), type: 'http_request', method, path, status, duration_ms: duration, }) );}
export function logError(error: Error, context: string) { console.error( JSON.stringify({ timestamp: new Date().toISOString(), type: 'error', context, message: error.message, stack: error.stack, }) );}Monitoring Key Metrics
Track important metrics in your API routes:
import { defineEventHandler } from 'h3';import { logRequest } from '../../utils/logger';
export default defineEventHandler(async (event) => { const startTime = Date.now();
try { const articles = [ { id: 1, title: 'Article 1', content: 'Content...' }, ];
const duration = Date.now() - startTime; logRequest('GET', '/api/articles', 200, duration);
return articles; } catch (error) { const duration = Date.now() - startTime; logRequest('GET', '/api/articles', 500, duration); throw error; }});Custom Domains
To use a custom domain with your Klutch.sh-deployed Analog app:
1. Add the Domain in Klutch.sh
In the Klutch.sh dashboard, go to your app’s settings and add your custom domain (e.g., app.example.com).
2. Update Your DNS Provider
Update your DNS records with the CNAME provided by Klutch.sh:
CNAME: app.example.com → example-app.klutch.sh3. Wait for DNS Propagation
DNS changes can take up to 48 hours to propagate. Use tools to verify:
nslookup app.example.com# ordig app.example.comOnce propagated, your Analog app will be accessible at your custom domain with automatic HTTPS.
Troubleshooting
Issue 1: App Fails to Build
Error: npm ERR! ERR! code ENOENT
Solutions:
- Ensure
package.jsonexists in the repository root. - Verify all npm scripts are correctly defined (especially
buildandstart). - Check that all required dependencies are listed in
package.json. - Clear the cache and rebuild:
rm -rf node_modules package-lock.json && npm install
Issue 2: Port Binding Error
Error: EADDRINUSE: address already in use :::3000
Solutions:
- Ensure the internal port in Klutch.sh matches the port your Analog server uses.
- Check that no other process is using port 3000 locally.
- Set the
PORTenvironment variable in your app if using a custom port.
Issue 3: Database Connection Fails
Error: connect ECONNREFUSED 127.0.0.1:5432
Solutions:
- Verify the
DATABASE_URLis correctly set in Klutch.sh environment variables. - Ensure the database service is running and accessible.
- Check database credentials and network connectivity.
- Test the connection locally before deploying.
Issue 4: Module Not Found
Error: Cannot find module '@analogjs/core'
Solutions:
- Run
npm installto ensure all dependencies are installed. - Clear the npm cache:
npm cache clean --force - Delete
node_modulesandpackage-lock.json, then reinstall. - Verify the
package.jsonincludes all required Analog dependencies.
Issue 5: Environment Variables Not Loaded
Error: process.env is undefined or missing values
Solutions:
- Ensure environment variables are set in the Klutch.sh dashboard.
- Redeploy the app after adding new environment variables.
- Use
console.log(process.env)in your code to debug (remove before production). - For client-side code, use
import.meta.envinstead ofprocess.env.
Best Practices
1. Use Environment Variables for Configuration
Never hardcode sensitive information or environment-specific values:
// Goodconst apiUrl = process.env['API_URL'];const dbUrl = process.env['DATABASE_URL'];
// Avoidconst apiUrl = 'https://api.hardcoded.com';const dbUrl = 'postgresql://user:pass@localhost:5432/db';2. Implement Error Handling
Handle errors gracefully in your API routes and components:
// Goodexport default defineEventHandler(async (event) => { try { const data = await fetchData(); return data; } catch (error) { event.node.res.statusCode = 500; return { error: 'Internal server error' }; }});
// Avoidexport default defineEventHandler(async (event) => { return await fetchData(); // No error handling});3. Cache Expensive Operations
Use Redis to cache database queries and API responses:
// Goodconst cached = await getCached('articles');if (cached) return cached;
const data = await queryDatabase();await setCached('articles', data, 3600);return data;
// Avoidreturn await queryDatabase(); // Every request hits the database4. Use Compression Middleware
Enable compression for faster data transfer:
import { defineEventHandler } from 'h3';
export default defineEventHandler((event) => { event.node.res.setHeader('Accept-Encoding', 'gzip, deflate, br');});5. Optimize Images and Assets
Minimize and optimize static assets:
# Use tools like imagemin for imagesnpx imagemin src/assets/*.png --out-dir=dist/assets
# Use ESBuild for JavaScript optimization (Vite does this automatically)6. Monitor Performance
Track response times and error rates:
const metrics = { requests: 0, errors: 0, totalTime: 0,};
export default defineEventHandler((event) => { const startTime = Date.now();
event.node.res.on('finish', () => { metrics.requests++; metrics.totalTime += Date.now() - startTime; if (event.node.res.statusCode >= 400) { metrics.errors++; } });});7. Keep Dependencies Updated
Regularly update Analog and Angular to the latest versions:
npm outdatednpm updatenpm audit fix8. Use TypeScript Strict Mode
Enable strict type checking to catch errors early:
{ "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true }}9. Implement Proper Testing
Add unit and integration tests:
ng generate service articleng generate component article-listnpm test10. Document Your API
Document your API routes and environment variables:
/** * GET /api/articles * Retrieves all articles with optional filtering * * Query Parameters: * - limit: number (default: 10) * - offset: number (default: 0) * * Response: Array<Article> */export default defineEventHandler(async (event) => { // Implementation});Verifying Your Deployment
After deployment completes:
-
Check the App URL: Visit your app at
https://example-app.klutch.shor your custom domain. -
Verify Pages Render: Ensure all pages load and render correctly.
-
Test API Routes: Test your API endpoints with curl or a REST client:
Terminal window curl https://example-app.klutch.sh/api/articlescurl -X POST https://example-app.klutch.sh/api/articles \-H "Content-Type: application/json" \-d '{"title":"New Article","content":"..."}' -
Check Health Endpoint: Verify the health check endpoint:
Terminal window curl https://example-app.klutch.sh/api/health -
Review Logs: Check the Klutch.sh dashboard for deployment logs and any errors.
If your app doesn’t work as expected, review the troubleshooting section and check the logs in the Klutch.sh dashboard.
External Resources
- Official Analog Documentation
- Angular Framework Documentation
- Vite Documentation
- Klutch.sh Official Website
- Node.js Documentation
- H3 HTTP Framework Documentation
- Redis Documentation
Deploying an Analog app to Klutch.sh is straightforward with Nixpacks for automatic deployment or Docker for fine-grained control. By following this guide, you’ve learned how to scaffold an Analog project, configure environment variables, implement security best practices, set up monitoring, and troubleshoot common issues. Your Analog application is now running on Klutch.sh’s global infrastructure with automatic HTTPS, custom domain support, and persistent storage capabilities. For additional help or questions, consult the official Analog documentation or contact Klutch.sh support.