Developing Data Apps Locally logo

Developing Data Apps Locally

OrganizationPopular
lightdash
developing-data-apps-locally

Use when editing a locally created or downloaded Lightdash data app — how local editing, building, and uploading work, and what is read-only.

Overview

Publisherlightdash
Repositorylightdash
Skill namedeveloping-data-apps-locally
Stars
6.1K
Forks
778
Bundled files
Instructions only
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by lightdash on GitHub. Read the source before you install it.

Installation

Install the Developing Data Apps Locally AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/lightdash/lightdash.git /tmp/lightdash
mkdir -p .claude/skills
cp -r /tmp/lightdash/packages/cli/src/handlers/apps/authoring/developing-data-apps-locally .claude/skills/developing-data-apps-locally
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Developing Data Apps Locally in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Developing Data Apps Locally on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Developing Data Apps Locally is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Developing Lightdash Data Apps Locally

You are editing a Lightdash data app that was created or downloaded with the Lightdash CLI.

The only way to reach data is the SDK

  • All app data access goes through @lightdash/query-sdk. Deployed apps use Lightdash's postMessage bridge; lightdash apps preview uses a loopback proxy restricted to the same SDK routes and project. Do not add direct fetch or REST calls.
  • For the SDK surface (query builder, useLightdash, filters, downloads), read the lightdash-data-app skill in this folder.

External HTTP APIs go through linked connections

  • The one sanctioned path to a third-party API is lightdash.externalFetch('<alias>', ...) against an external connection a project admin configured and linked to this app (see the lightdash-data-app skill).
  • The app's links are declared in this folder's lightdash-app.yml under externalConnections (- alias: stripe / connectionSlug: stripe-api). When the key is present, upload reconciles the app's links to match it exactly — so to link a connection that already exists in the project, add its {alias, connectionSlug} entry and upload. Do not remove entries casually: an entry removed from the list (or an empty list) unlinks on upload, and a manifest without the key leaves links unchanged.
  • Watch the upload output: a connectionSlug that doesn't exist in the target project is skipped with a warning (the app uploads, but externalFetch on that alias fails at runtime). Linking requires either the admin-level manage:ExternalConnection permission or an admin-enabled connection plus permission to manage the target data app — if a link is skipped or forbidden, report it to the user instead of retrying.
  • If the app needs an API with no existing connection, stop and say so — do not vendor an HTTP client or try to reach it another way. An admin must create the connection first (in project settings, or as code: lightdash download --include-external-connections, edit lightdash/external-connections/<slug>.yml, lightdash upload with the secret in LIGHTDASH_EXTERNAL_CONNECTION_SECRET_<SLUG>); then it can be linked via the manifest as above.

Library boundaries — build with what's preinstalled

  • The app builds against a fixed template dependency set — see package.json (React, Recharts, d3 + d3-cloud/d3-sankey, Radix primitives, Tailwind, lucide-react, date-fns, html-to-image, jspdf, and more). Design within this set; it covers almost all data-app needs.
  • Adding new npm packages only works when the Lightdash organization has custom dependencies enabled — assume it does not. When disabled, upload rejects new dependency declarations. Do not attempt pnpm add to find out; ask the user whether their organization has custom dependencies enabled before considering a new library.
  • Do not work around a missing library by vendoring its source into src/, inlining minified code, or fetching code at runtime. If the template set genuinely cannot express what's asked, say so and let the user decide.

The edit → build → upload loop

Run these commands from this folder under apps/<slug>/. The upload path ../.. selects the Lightdash content root.

  1. Edit files under src/ only.
  2. Run lightdash apps validate to check the source, manifest, dependencies, external-connection aliases, and semantic references against the downloaded context. Use lightdash apps validate --build to add the Cloud-parity Vite production build; use --live to check against fresh project explores or --format json in CI. A green run reports any call sites it could not fully analyze instead of silently claiming complete coverage.
  3. lightdash upload --apps <slug> --path ../.. (the slug from this folder's lightdash-app.yml) — the server rebuilds and serves the app. The server rebuild remains the final result that ships.

Cloud-parity local builds

  • lightdash apps validate --build assembles src/ in an isolated copy of the CLI's trusted template and invokes bare vite build — it deliberately does not typecheck because the Cloud build does not typecheck.
  • Apps made with lightdash apps create already have the standard template dependencies installed. After lightdash download, run npm install before requesting --build if node_modules is absent. Validation does not install the standard dependency set implicitly.
  • Apps with custom dependencies are restored into the isolated build directory with pnpm install --frozen-lockfile --ignore-scripts, matching Cloud. An install or Vite failure is a validation error, includes the command output, and exits non-zero.
  • Do not modify machine configuration, .npmrc files, registry settings, or the project's dependency files to force the check to pass. The server rebuild on upload remains authoritative.
  • Exception — adding a dependency (only for organizations with custom dependencies enabled — see "Library boundaries" above). This is the one workflow that still requires pnpm: upload rejects new dependencies unless pnpm-lock.yaml was regenerated to match package.json, so dependency resolution MUST succeed locally. Use pnpm add <pkg> — prefixed with Socket Firewall when available (sfw pnpm add <pkg>; check with command -v sfw) to block known-malicious packages — or after editing package.json run pnpm install --lockfile-only (updates the lockfile without installing). If resolution fails, stop and report the exact pnpm error to the user — never hand-edit package.json and proceed without the lockfile; the upload will fail.
  • Never run dependency lifecycle scripts. The app's .npmrc sets ignore-scripts=true — leave it. A downloaded app can be authored by someone else, and their dependencies' install scripts must not execute on this machine. Explicit npm run build/npm run dev and pnpm build/pnpm dev commands still work.

Preview locally against real data

lightdash apps preview (run in this folder) starts a local dev server that renders the app against the Lightdash instance you are logged into, using your CLI credential. Requires npm install to have succeeded; if it hasn't, skip preview and rely on the server rebuild.

  • Preview does not pass your API key to vite or browser code: the CLI holds it behind a loopback proxy that only forwards the SDK route allowlist (query execution, result polling, downloads, current user), pinned to this app's project. No credential is written to the app folder. Never put a real key in .env.local or any VITE_-prefixed var — anything VITE_* is inlined into the page and readable by any code running there.
  • There is no manual npm run dev equivalent with data access — bare npm run dev starts the page but API calls fail with 401. Always use lightdash apps preview.
  • An endpoint that works in preview but not when deployed means it is outside the data-app SDK surface — use the SDK, don't work around the proxy.
  • Declared custom dependencies work in preview too — the dev server bundles whatever the dependency install put in node_modules, the same set the server installs on upload.
  • Preview shows your data under your permissions and user attributes — viewers of the deployed app may see different data. Do not treat preview as verification of viewer-specific behavior.
  • Local preview keeps the credential out of the app environment/browser but is not a sandbox: vite and the downloaded tooling execute as your OS user, can read that user's files (including the existing CLI config), and the app can read the query results it requests. Only preview source and dependencies you trust.
  • The dev server applies a CSP that forces API traffic through its same-origin proxy, but script-src stays permissive (vite needs it), so preview is not a full stand-in for the deployed Content-Security-Policy. A library that works in preview may still be blocked when deployed; the app page after upload is the final check.
  • Host-mediated features are not emulated locally. External connections (externalFetch), data-app-viz row/field context, Google Sheets export, the product inspector, and product URL-state integration must be tested after upload.

Project context (read-only reference)

.lightdash/context/ holds a point-in-time snapshot of the source project:

  • models/ — the semantic layer, one YAML file per model: the real tables/dimensions/metrics you can query. Use these exact names. Start with models/_index.md, then read only the model files you need. (Apps downloaded with an older CLI carry the whole semantic layer in semantic-layer.yml instead and have no models/.)
  • parameters.yml — project-wide parameters (if any).
  • prompt-history.md — the prompts used to generate each version.
  • theme/ — styling instructions and assets.

Read-only files

Most root config is reference only — editing it has no effect because the server rebuilds against its trusted template. This applies to vite.config.js, tailwind.config.js, tsconfig.json, and other build/tooling files.

package.json is partially editable only when custom dependencies are enabled for the Lightdash organization — see "Library boundaries" above; treat it as read-only otherwise. When enabled, you may add npm dependencies with pnpm add <pkg> — registry packages with plain semver versions only (no git/file/url specs), up to 60 direct dependencies, and pnpm-lock.yaml must be updated alongside (see the exception above — this is the one step that still requires pnpm and must succeed locally). On upload the CLI warns which packages will be installed in the build sandbox; install scripts never run. Other root config (vite/tailwind/tsconfig) remains read-only.

Frequently asked questions

What does the Developing Data Apps Locally AI skill do?

Use when editing a locally created or downloaded Lightdash data app — how local editing, building, and uploading work, and what is read-only.

Why use Developing Data Apps Locally on TypingMind?

Because you install it once and use it with any model. Developing Data Apps Locally is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Developing Data Apps Locally in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/lightdash/lightdash/tree/main/packages/cli/src/handlers/apps/authoring/developing-data-apps-locally. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Developing Data Apps Locally?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Developing Data Apps Locally?

As many as you like. As long as a model supports skills, you can use Developing Data Apps Locally with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Developing Data Apps Locally AI skill free?

It is published on GitHub by lightdash. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇