LakeQL
Introduction
  • Overview
  • Key Concepts
  • Package Map
Getting Started
  • Prerequisites
  • Quickstart
  • Environment Configuration
  • First Run
Architecture
  • System Overview
  • Data Flow
  • Request Lifecycle
Configuration
  • Environment Variables
  • Authentication
  • Trino Connection
create-app
  • Usage
  • Template Structure
  • Post Creation
Contributing
  • Local Development
  • Contribution Guide
Guides
  • Custom Resolvers
  • Extending Schema
  • Deploying
  • Mutations
  • Load Strategies
GitHub
LakeQL
  1. LakeQL
  2. create-app
  3. Template Structure

On this page

  1. Project Layout
  2. File Details
    1. src/index.ts
    2. src/config.ts
    3. src/auth.ts
    4. src/permissions.ts
    5. src/env.ts
    6. src/config-registry.ts
    7. .env.example
    8. package.json
    9. lakeql.config.json

Template Structure

Understand the project layout created by @lakeql/create-app.

Project Layout #

After scaffolding, your project has this structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my-lakeql-project/
├── src/
│   ├── index.ts             # Entry point — starts the API server
│   ├── config.ts            # defineConfig with runtime options
│   ├── auth.ts              # Custom getUser resolver
│   ├── permissions.ts       # Permission rules for technical users
│   ├── env.ts               # Environment variable validation (t3-env + Zod)
│   ├── config-registry.ts   # Auto-generated config index (empty initially)
│   └── schemas/             # Generated schemas go here after pull
│       └── generated/
├── .env.example             # Template environment variables
├── .nvmrc                   # Node.js major version used by the template
├── package.json             # Dependencies and scripts
├── tsconfig.json            # TypeScript configuration
├── tsdown.config.ts         # Build configuration
└── lakeql.config.json       # LakeQL CLI configuration

File Details #

src/index.ts #

The entry point that starts the API server using the defined configuration:

1
2
3
4
import { config } from "./config"

await config.startServer()

src/config.ts #

Configures the API server with defineConfig. This is where you wire together auth, permissions, and schema loading:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { defineConfig } from "@lakeql/api/config"

import { getUser } from "./auth"
import { allConfigs } from "./config-registry"
import { permissions } from "./permissions"

const baseDir = import.meta.dirname

export const config = defineConfig({
  allConfigs,
  baseDir,
  getUser,
  graphqlPath: "/graphql",
  healthCheckEndpoint: "/live",
  permissions,
  port: 4000,
  schemaPath: "./schemas",
})

The schemaPath is resolved relative to baseDir (the src/ directory). Generated schemas placed in src/schemas/ are loaded automatically at startup.

src/auth.ts #

A starter authentication resolver. By default, it supports mock auth for local development:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import type { GetUserResolver } from "@lakeql/api/types"

import { env } from "./env"

export const getUser: GetUserResolver = async (request) => {
  const authHeader = request.headers.get("authorization")

  if (authHeader) {
    if (env.AUTH_MOCK && authHeader === env.AUTH_MOCK_TOKEN) {
      return { userName: "testuser" }
    }
    return null
  }

  return null
}

Replace this with real JWT verification (e.g. using jose) for production.

src/permissions.ts #

Defines per-user permission rules for technical users. Initially empty — add rules as needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { createPermission as createPermissionFromApi } from "@lakeql/api/helpers"

import { allConfigs } from "./config-registry"

const createPermission = createPermissionFromApi(allConfigs)

export const permissions = [
  // {
  //   name: "testuser",
  //   useSystemUser: false,
  //   permissions: {
  //     Query: [createPermission("hive", "schema_name", ["table_name"])],
  //     Mutation: [],
  //   },
  // },
]

src/env.ts #

Validates environment variables at startup using @t3-oss/env-core with Zod schemas. If a required variable is missing or invalid, the process exits with a clear error message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import { createEnv } from "@t3-oss/env-core"
import { coerce, number, string, enum as zodEnum } from "zod"

export const env = createEnv({
  runtimeEnv: process.env,
  server: {
    API_LOGGER: zodEnum(["debug", "info", "warn", "error", "silent"]).default(
      "warn"
    ),
    API_PORT: coerce.number().default(4000),
    AUTH_MOCK: coerce.boolean().default(false),
    AUTH_MOCK_TOKEN: string().optional(),
    HIVE_CATALOG: string().min(1),
    HIVE_HOST: string(),
    HIVE_PASSWORD: string().min(1),
    HIVE_PORT: string()
      .transform((s) => Number.parseInt(s, 10))
      .pipe(number()),
    HIVE_SOURCE: string().optional(),
    HIVE_USERNAME: string().min(1),
    NODE_ENV: zodEnum(["development", "production", "test"]).default(
      "development"
    ),
  },
})

src/config-registry.ts #

Auto-generated by lakeql-cli create-registry (or automatically after pull). Initially empty — populated once you pull schemas:

1
2
3
4
5
6
export const allConfigs = [] as const

export type AvailableCatalogs = (typeof allConfigs)[number]["catalog"]
export type AvailableSchemas = (typeof allConfigs)[number]["schema"]
export type AvailableTables = (typeof allConfigs)[number]["tableName"]

After pulling schemas, it looks like:

1
2
3
4
import { ordersConfig } from "./schemas/generated/hive/sales/orders/config"

export const allConfigs = [ordersConfig] as const

.env.example #

Template for required environment variables:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22######
# Hive Database
######
HIVE_HOST="http://localhost"
HIVE_PORT=8080
HIVE_CATALOG=hive
HIVE_USERNAME=admin
HIVE_PASSWORD="secret123"
HIVE_SOURCE="lakeql"

######
# Mock
######
AUTH_MOCK=true
AUTH_MOCK_TOKEN="1234"

######
# GraphQL API
######
API_PORT=4000
API_LOGGER="warn"

package.json #

Pre-configured with LakeQL packages and development tooling:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31{
  "name": "lakeql-app",
  "type": "module",
  "scripts": {
    "build": "tsdown",
    "dev": "pnpm with-env tsx ./src/index.ts",
    "preview": "pnpm with-env node ./dist/index.mjs",
    "start": "node ./dist/index.mjs",
    "typecheck": "tsc --noEmit",
    "with-env": "dotenv -e ./.env --",
    "cli": "pnpm with-env lakeql-cli"
  },
  "dependencies": {
    "@lakeql/api": "^latest",
    "@lakeql/query-builder": "^latest",
    "@lakeql/trino-client": "^latest",
    "@t3-oss/env-core": "^latest",
    "zod": "^latest"
  },
  "devDependencies": {
    "@lakeql/cli": "^latest",
    "dotenv-cli": "^latest",
    "tsdown": "^latest",
    "tsx": "^latest",
    "typescript": "^latest"
  },
  "engines": {
    "node": ">=24"
  }
}

Key scripts:

ScriptCommandPurpose
devpnpm with-env tsx ./src/index.tsDevelopment with env vars loaded
buildtsdownProduction build
startnode ./dist/index.mjsRun production build
previewpnpm with-env node ./dist/index.mjsRun production build with .env
clipnpm with-env lakeql-cliLakeQL CLI with env vars loaded

lakeql.config.json #

Configures the CLI's code generation output path:

1
2
3
4
{
  "sourcePath": "src"
}

This tells the CLI to write generated files relative to src/, resulting in paths like src/schemas/generated/{catalog}/{schema}/{table}/.

Previous page

Usage

Next page

Post Creation

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31