Skip to content

Getting Started with InfluxDB

13 min readInfluxDBDatabasesTime Series

Short version: npm i -g layerbase then lbase create influx1 -e influxdb --start gives you a local InfluxDB 3, and lbase url influx1 prints the URL the client needs. A managed instance comes from Layerbase Cloud, where InfluxDB is a Performance engine and runs always-on on the Pro plan.

Every database can store rows with a timestamp column. PostgreSQL, MySQL, SQLite: they all let you INSERT a row with created_at. But time-series workloads have a distinct shape: massive write volumes, queries that always filter by time range, and data that loses value as it ages. General-purpose databases can handle this. They just weren't designed for it.

QuestDB tackles time-series by extending SQL with dedicated clauses like SAMPLE BY. InfluxDB comes at it from the write side. Instead of tables and rows, it gives you its own ingestion model: measurements, tags, and fields, written over HTTP with the line protocol, a compact text format built for high-throughput ingestion. Then it lets you read that data back with SQL and InfluxQL.

That last part is new. This guide targets InfluxDB 3, which has been generally available since April 2025 and is what Layerbase provisions today. Version 3 dropped Flux, the functional pipeline language that version 2 was built around. InfluxData's own docs say that "Flux is in maintenance mode and is not supported in InfluxDB 3" and point new code at SQL or InfluxQL instead. Everything below was tested against InfluxDB 3.10.5 running locally through the Layerbase CLI.

This makes InfluxDB a natural fit for server metrics, application telemetry, IoT sensor readings, and financial tick data. It handles very high write rates, keeps retention per database, and now answers with plain SQL, so the aggregation you already know how to write is the aggregation you write.

We'll build an application performance monitoring pipeline in one TypeScript file. Everything below works against a local instance, but you can also point it at Layerbase Cloud if you'd rather not install anything.

Contents

Create an InfluxDB Instance

Local with the Layerbase CLI

The Layerbase CLI, formerly SpinDB, handles the download, setup, and initial configuration in one command. No Docker, no manual binary management. (What is the Layerbase CLI?)

Install the Layerbase CLI globally:

bash
npm i -g layerbase    # npm
pnpm add -g layerbase # pnpm

Or run it directly without installing:

bash
npx layerbase create influx1 -e influxdb --start  # npm
pnpx layerbase create influx1 -e influxdb --start # pnpm

If you installed globally, create and start an InfluxDB instance:

bash
lbase create influx1 -e influxdb --start
text
✔ Container created
✔ Database cluster initialized
✔ InfluxDB started
✔ Database "influx1" created

The CLI downloads the InfluxDB 3 binary, starts the server, and creates a database named after the container. Verify it's running:

bash
lbase url influx1
text
http://127.0.0.1:8086

Two things about a local instance are worth knowing before you write any code.

There is no token. The CLI starts InfluxDB 3 Core with authentication off, so Authorization headers are optional locally. Cloud instances do use a token, and the code below has one variable for it that you leave empty on localhost.

A database replaces the version 2 bucket. Version 2 asked you to set up an organization, a bucket, and an API token before the first write. Version 3 asks for a database name, and it creates one on first write if it doesn't exist. There is no organization in the picture at all.

Confirm the version you got:

bash
curl -s http://127.0.0.1:8086/ping
json
{
  "product_name": "InfluxDB 3 Core",
  "version": "3.10.5",
  "revision": "df21654049",
  "process_id": "ccc158ef-2e48-4df7-9d45-605a7508108d"
}

Layerbase Cloud

Skip the local install entirely if you prefer. Layerbase Cloud provisions a managed InfluxDB 3 instance and hands you an HTTPS endpoint and an API token through the Quick Connect panel.

Cloud instances use TLS and a token, so the connection config changes in two places:

typescript
const client = new InfluxDBClient({
  host: 'https://your-host.cloud.layerbase.dev',
  token: 'YOUR_TOKEN',
  database: 'your-database',
})

The token goes out as Authorization: Token <token>, which is what the client sends by default and what the Layerbase endpoint expects. Everything else in this guide works identically whether you're running locally or on Layerbase Cloud.

Set Up the Project

bash
mkdir influxdb-metrics && cd influxdb-metrics
pnpm init
pnpm add @influxdata/influxdb3-client
pnpm add -D tsx typescript

Note the package name. @influxdata/influxdb-client is the version 2 client, built around organizations, buckets, and Flux. @influxdata/influxdb3-client is the version 3 one, and it's what the rest of this post uses.

Create a file called metrics.ts. All the code in this post goes into that one file.

The Data Model: Measurements, Tags, and Fields

Before writing any code, it helps to understand how InfluxDB thinks about data, because the write model is genuinely different from relational databases even though the read model is now SQL.

A measurement is the name you write points under. On the query side it is simply a table: SELECT ... FROM http_requests. Ours will be http_requests.

Tags are indexed key-value pairs. They describe what the data point is about: which endpoint, which HTTP method, which status code. Because they're indexed, filtering and grouping by tags is fast. Tags are always strings.

Fields are the actual values you're measuring: response time in milliseconds, bytes sent. Fields are not indexed. You query them with aggregation functions (avg, max, sum), not with equality filters.

Every data point also has a timestamp, which shows up in SQL as the time column.

Here's how our metrics map to this model:

ConceptInfluxDB termExample
Table nameMeasurementhttp_requests
Indexed metadataTagsmethod=GET, endpoint=/api/users, status_code=200
Measured valuesFieldsresponse_time_ms=42.5, bytes_sent=1024
WhenTimestamp2026-08-26T05:15:48Z

If you've used SQL databases, think of tags as columns you'd put in a WHERE clause and fields as columns you'd wrap in avg() or sum(). In version 3 you literally do write it that way.

Generate Metrics Data

We'll simulate HTTP request metrics for a web app. Each data point represents one request with its method, endpoint, status code, response time, and bytes sent:

typescript
import { InfluxDBClient, Point } from '@influxdata/influxdb3-client'

type Metric = {
  method: string
  endpoint: string
  statusCode: string
  responseTimeMs: number
  bytesSent: number
  timestamp: Date
}

function generateMetrics(): Metric[] {
  const endpoints = [
    { method: 'GET', endpoint: '/api/users', avgMs: 45, avgBytes: 2048 },
    { method: 'GET', endpoint: '/api/products', avgMs: 62, avgBytes: 4096 },
    { method: 'POST', endpoint: '/api/orders', avgMs: 120, avgBytes: 512 },
    { method: 'GET', endpoint: '/api/health', avgMs: 5, avgBytes: 128 },
    { method: 'PUT', endpoint: '/api/users', avgMs: 85, avgBytes: 256 },
  ]

  const metrics: Metric[] = []
  const now = new Date()
  const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000)

  for (let i = 0; i < 50; i++) {
    const ep = endpoints[Math.floor(Math.random() * endpoints.length)]
    const ts = new Date(oneHourAgo.getTime() + Math.random() * 60 * 60 * 1000)

    const jitter = 0.5 + Math.random() * 1.5
    const responseTimeMs = Math.round(ep.avgMs * jitter * 100) / 100
    const bytesSent = Math.round(ep.avgBytes * (0.8 + Math.random() * 0.4))

    const statusCode =
      Math.random() > 0.9 ? '500' : Math.random() > 0.85 ? '404' : '200'

    metrics.push({
      method: ep.method,
      endpoint: ep.endpoint,
      statusCode,
      responseTimeMs,
      bytesSent,
      timestamp: ts,
    })
  }

  return metrics.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())
}

const metrics = generateMetrics()
console.log(`Generated ${metrics.length} request metrics`)

Each endpoint has a realistic average response time and payload size. The jitter multiplier creates natural variance, about 10% of requests get error status codes, and the data spans one hour, sorted by timestamp.

Connect and Write Data

Now connect to InfluxDB and write the metrics using the Point builder:

typescript
const INFLUX_HOST = 'http://127.0.0.1:8086'
const INFLUX_DATABASE = 'influx1'
const INFLUX_TOKEN = ''

const client = new InfluxDBClient({
  host: INFLUX_HOST,
  token: INFLUX_TOKEN,
  database: INFLUX_DATABASE,
})

const points = metrics.map((m) =>
  Point.measurement('http_requests')
    .setTag('method', m.method)
    .setTag('endpoint', m.endpoint)
    .setTag('status_code', m.statusCode)
    .setFloatField('response_time_ms', m.responseTimeMs)
    .setIntegerField('bytes_sent', m.bytesSent)
    .setTimestamp(m.timestamp),
)

await client.write(points, INFLUX_DATABASE, undefined, { precision: 'ms' })
console.log(`Wrote ${points.length} points to InfluxDB`)
text
Generated 50 request metrics
Wrote 50 points to InfluxDB

On Layerbase Cloud, INFLUX_HOST becomes the https:// endpoint from Quick Connect and INFLUX_TOKEN becomes the token shown next to it. Locally you leave the token empty.

A few things worth noting:

  • Point.measurement() starts a builder. Chain .setTag() for indexed metadata and .setFloatField() / .setIntegerField() for measured values. This maps directly to the line protocol InfluxDB uses on the wire.
  • client.write() takes an array, so a batch is one HTTP request. There's no separate write API object to remember to close, which is a real improvement over the version 2 client where forgetting writeApi.close() silently dropped points.
  • precision: 'ms' tells InfluxDB to interpret timestamps as milliseconds. The default is nanoseconds.
  • Tags vs fields: method, endpoint, and status_code are tags because we'll filter and group by them. response_time_ms and bytes_sent are fields because we'll aggregate them.

The line protocol is just text, so nothing stops you from writing with curl when you're debugging:

bash
curl -X POST "http://127.0.0.1:8086/api/v3/write_lp?db=influx1&precision=millisecond" \
  --data-binary 'http_requests,method=GET,endpoint=/api/users,status_code=200 response_time_ms=42.5,bytes_sent=1024i'

That returns 204 No Content on success. The version 2 endpoint /api/v2/write?bucket=... still works on version 3 as a compatibility path, which is why existing Telegraf configs and version 2 SDK writers keep working after an upgrade.

Query with SQL

This is the part that changed. InfluxDB 3 answers SQL, so fetching recent requests is a SELECT:

typescript
const recentSql = `
  SELECT time, method, endpoint, status_code, response_time_ms
  FROM http_requests
  WHERE time > now() - INTERVAL '1 hour'
  ORDER BY time
  LIMIT 10
`

console.log('\nRecent requests (first 10):')
console.log('time                    | method | endpoint        | status | ms')
console.log('------------------------|--------|-----------------|--------|------')

for await (const row of client.query(recentSql, INFLUX_DATABASE)) {
  const time = new Date(Number(row.time)).toISOString().slice(0, 23)
  const method = String(row.method).padEnd(6)
  const endpoint = String(row.endpoint).padEnd(15)
  const status = String(row.status_code).padEnd(6)
  const ms = Number(row.response_time_ms).toFixed(1).padStart(6)
  console.log(`${time} | ${method} | ${endpoint} | ${status} | ${ms}`)
}
text
Recent requests (first 10):
time                    | method | endpoint        | status | ms
------------------------|--------|-----------------|--------|------
2026-08-26T04:57:01.664 | PUT    | /api/users      | 200    |   95.0
2026-08-26T04:58:42.377 | PUT    | /api/users      | 200    |  162.9
2026-08-26T04:59:46.103 | GET    | /api/health     | 200    |    4.7
2026-08-26T05:00:10.503 | GET    | /api/health     | 200    |    3.8
2026-08-26T05:02:43.429 | PUT    | /api/users      | 200    |   62.7
2026-08-26T05:05:39.387 | GET    | /api/users      | 200    |   39.2
2026-08-26T05:08:45.261 | POST   | /api/orders     | 500    |  201.7
2026-08-26T05:11:32.784 | POST   | /api/orders     | 404    |  200.1
2026-08-26T05:14:58.480 | POST   | /api/orders     | 200    |  198.8
2026-08-26T05:15:48.223 | GET    | /api/products   | 404    |   50.2

client.query() returns an async generator of plain objects, one per row, with tags and fields as ordinary columns. The time column comes back as epoch milliseconds, so wrap it in new Date() before formatting.

Aggregation: Average Response Time per Window

Version 2 had aggregateWindow(every: 5m, fn: mean). Version 3 uses the SQL function date_bin, which rounds each timestamp down to the start of its window so you can group on it:

typescript
const windowSql = `
  SELECT
    date_bin(INTERVAL '5 minutes', time) AS window_start,
    avg(response_time_ms) AS avg_ms,
    count(*) AS requests
  FROM http_requests
  WHERE time > now() - INTERVAL '1 hour'
  GROUP BY window_start
  ORDER BY window_start
`

console.log('\nAverage response time per 5-minute window:')
console.log('window | avg_ms | requests')
console.log('-------|--------|---------')
for await (const row of client.query(windowSql, INFLUX_DATABASE)) {
  const w = new Date(Number(row.window_start)).toISOString().slice(11, 16)
  const avgMs = Number(row.avg_ms).toFixed(1).padStart(6)
  const n = String(row.requests).padStart(8)
  console.log(`${w}  | ${avgMs} | ${n}`)
}
text
Average response time per 5-minute window:
window | avg_ms | requests
-------|--------|---------
04:55  |   87.5 |        3
05:00  |   33.3 |        2
05:05  |  120.4 |        2
05:10  |  199.4 |        2
05:15  |  126.9 |        2
05:20  |   52.4 |        4
05:25  |  103.5 |        3
05:30  |   76.7 |        4
05:35  |   69.6 |        7
05:40  |   50.6 |        6
05:45  |  108.4 |        8
05:50  |   71.3 |        5
05:55  |   46.3 |        2

Swap '5 minutes' for '1 hour' or '1 day'. Swap avg for max, min, sum, or count. Windows with no data simply don't appear, which is what createEmpty: false used to do for you in Flux.

This is also where the version 3 read model pays off: count(*) alongside avg() in the same result is one more column, not a second query joined by hand.

Grouping: Response Times by Endpoint

Compare how different endpoints perform by grouping on the endpoint tag. It's GROUP BY, exactly as you'd expect:

typescript
const byEndpointSql = `
  SELECT
    endpoint,
    avg(response_time_ms) AS avg_ms,
    max(response_time_ms) AS max_ms,
    count(*) AS requests
  FROM http_requests
  WHERE time > now() - INTERVAL '1 hour'
  GROUP BY endpoint
  ORDER BY avg_ms DESC
`

console.log('\nResponse time by endpoint:')
console.log('endpoint          | avg_ms | max_ms | requests')
console.log('------------------|--------|--------|---------')
for await (const row of client.query(byEndpointSql, INFLUX_DATABASE)) {
  const endpoint = String(row.endpoint).padEnd(17)
  const avgMs = Number(row.avg_ms).toFixed(1).padStart(6)
  const maxMs = Number(row.max_ms).toFixed(1).padStart(6)
  const n = String(row.requests).padStart(8)
  console.log(`${endpoint} | ${avgMs} | ${maxMs} | ${n}`)
}
text
Response time by endpoint:
endpoint          | avg_ms | max_ms | requests
------------------|--------|--------|---------
/api/orders       |  198.2 |  225.9 |        9
/api/users        |   78.7 |  162.9 |       19
/api/products     |   74.2 |  120.2 |       11
/api/health       |    5.5 |    9.1 |       11

Group by both dimensions at once for a per-endpoint time series, which is what you'd feed a dashboard:

sql
SELECT
  date_bin(INTERVAL '15 minutes', time) AS window_start,
  endpoint,
  avg(response_time_ms) AS avg_ms
FROM http_requests
WHERE time > now() - INTERVAL '1 hour'
GROUP BY window_start, endpoint
ORDER BY window_start, endpoint

InfluxQL, If You Prefer It

InfluxQL is the other supported language, and it's the one to reach for if you're porting queries from InfluxDB 1.x or wiring up a tool that already speaks it. Same client, one option:

typescript
const influxQl = `
  SELECT mean(response_time_ms)
  FROM http_requests
  WHERE time > now() - 1h
  GROUP BY time(15m), endpoint
`

for await (const row of client.query(influxQl, INFLUX_DATABASE, {
  type: 'influxql',
})) {
  console.log(JSON.stringify(row))
}
text
{"iox::measurement":"http_requests","time":1787719500000,"endpoint":"/api/health","mean":4.66}
{"iox::measurement":"http_requests","time":1787720400000,"endpoint":"/api/health","mean":3.77}
{"iox::measurement":"http_requests","time":1787721300000,"endpoint":"/api/health","mean":5.2}
{"iox::measurement":"http_requests","time":1787722200000,"endpoint":"/api/health","mean":5.89}
{"iox::measurement":"http_requests","time":1787723100000,"endpoint":"/api/health","mean":6.28}
{"iox::measurement":"http_requests","time":1787719500000,"endpoint":"/api/orders","mean":null}

GROUP BY time(15m) is the InfluxQL spelling of date_bin. Note the shape difference: InfluxQL emits one series per tag combination and fills empty windows with null, while the SQL path returns a flat result set and skips empty windows. Pick whichever shape your consumer wants.

Querying Without the SDK

The version 3 client sends queries over Arrow Flight, which is gRPC. That's fast, and it's the right default in an application. It is not always the right default in a serverless function, a CI job, or anywhere gRPC is awkward, so InfluxDB 3 also exposes plain HTTP query endpoints that return JSON:

typescript
async function querySql<T>(sql: string): Promise<T[]> {
  const res = await fetch(`${INFLUX_HOST}/api/v3/query_sql`, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      ...(INFLUX_TOKEN ? { authorization: `Token ${INFLUX_TOKEN}` } : {}),
    },
    body: JSON.stringify({ db: INFLUX_DATABASE, q: sql, format: 'json' }),
  })
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`)
  return (await res.json()) as T[]
}

type EndpointRow = { endpoint: string; avg_ms: number; requests: number }

const rows = await querySql<EndpointRow>(`
  SELECT endpoint, avg(response_time_ms) AS avg_ms, count(*) AS requests
  FROM http_requests
  WHERE time > now() - INTERVAL '1 hour'
  GROUP BY endpoint
  ORDER BY avg_ms DESC
`)
text
/api/orders     |  198.2 |    9
/api/users      |   78.7 |   19
/api/products   |   74.2 |   11
/api/health     |    5.5 |   11

/api/v3/query_influxql is the same endpoint for the other language. Both accept format: 'json', 'jsonl', or 'csv'.

For one-off checks from a terminal, the Layerbase CLI will run the query for you and print a table:

bash
lbase query influx1 "SELECT endpoint, avg(response_time_ms) AS avg_ms FROM http_requests GROUP BY endpoint"
text
endpoint      | avg_ms
--------------+-------------------
/api/orders   | 198.24777777777774
/api/products | 74.19454545454545
/api/users    | 78.69473684210526
/api/health   | 5.530000000000001

(4 rows)

On Layerbase Cloud the query console does the same thing in the browser, and it accepts both SQL and raw REST calls in the same editor.

Retention and Downsampling

InfluxDB can automatically delete data older than a configured threshold. In version 3 that setting lives on the database, not on a bucket, and you set it with the influxdb3 CLI that ships alongside the server:

bash
influxdb3 create database --host http://127.0.0.1:8086 --retention-period 7d metrics_raw
text
Database "metrics_raw" created successfully

Change it later without recreating anything:

bash
influxdb3 update database --host http://127.0.0.1:8086 --database influx1 --retention-period 30d
text
Database "influx1" updated successfully

A database created implicitly by a write, which is what happens the first time you run the script above, has no retention period and keeps data until you set one. That's fine for development and worth fixing before production.

In production, the common pattern is downsampling: keep high-resolution data briefly and aggregated summaries longer. For example:

  1. Raw database (7-day retention): every individual request metric
  2. 15-minute rollups (90-day retention): mean, max, and count per endpoint per window
  3. Daily rollups (no expiry): daily aggregates for long-term trend analysis

Here's the honest part. Version 2 did this with Flux tasks, a scheduled query with a |> to(bucket: ...) on the end, and version 3 has no equivalent because it has no Flux. InfluxDB 3 ships a Processing Engine that runs Python plugins on a schedule inside the server, which is the closest replacement, but it only exists when the server is started with a plugin directory configured, and the Layerbase CLI does not enable it.

What works everywhere, including a managed instance, is doing the rollup from your own code: read an aggregate, write it back as points. It's about fifteen lines.

typescript
const rollupSql = `
  SELECT
    date_bin(INTERVAL '15 minutes', time) AS window_start,
    endpoint,
    avg(response_time_ms) AS avg_ms,
    max(response_time_ms) AS max_ms,
    count(*) AS requests
  FROM http_requests
  WHERE time > now() - INTERVAL '1 hour'
  GROUP BY window_start, endpoint
`

const rollups: Point[] = []
for await (const row of client.query(rollupSql, INFLUX_DATABASE)) {
  rollups.push(
    Point.measurement('http_requests_15m')
      .setTag('endpoint', String(row.endpoint))
      .setFloatField('avg_ms', Number(row.avg_ms))
      .setFloatField('max_ms', Number(row.max_ms))
      .setIntegerField('requests', Number(row.requests))
      .setTimestamp(new Date(Number(row.window_start))),
  )
}

await client.write(rollups, 'influx1_hourly', undefined, { precision: 'ms' })
console.log(`Wrote ${rollups.length} rollup points to influx1_hourly`)
text
Wrote 17 rollup points to influx1_hourly

Rollup table (first 8 rows):
window | endpoint        | avg_ms | requests
-------|-----------------|--------|---------
04:45  | /api/health     |    4.7 |        1
04:45  | /api/users      |  162.9 |        1
05:00  | /api/health     |    3.8 |        1
05:00  | /api/orders     |  200.2 |        3
05:00  | /api/users      |   51.0 |        2
05:15  | /api/health     |    5.2 |        2
05:15  | /api/orders     |  214.7 |        2
05:15  | /api/products   |   62.4 |        3

Create influx1_hourly with a longer retention period first, run the rollup on a cron or a queue worker, and the raw database expires underneath it while the summaries persist. Full detail for recent data, compact summaries for historical analysis.

When to Reach for InfluxDB

I'd reach for InfluxDB in these situations:

  • Server and infrastructure monitoring: CPU, memory, disk I/O, network throughput. InfluxDB is the storage backend for Telegraf, one of the most widely deployed metrics agents.
  • Application performance metrics: request latency, error rates, throughput per endpoint. The tag-based model maps naturally to the dimensions you care about (service, endpoint, region, status code).
  • IoT sensor data at scale: thousands of devices reporting temperature, pressure, GPS, battery level. Tags identify the device, fields carry the readings, per-database retention keeps storage bounded.
  • Financial tick data: high-frequency price updates, trade volumes, order book snapshots. Very high write rates, with rolling averages, VWAP, or volatility over configurable windows.
  • Any workload with high-frequency timestamped writes and time-windowed queries: if your data arrives continuously, your queries always filter by time range, and you want retention handled for you, this is exactly what InfluxDB was built for.

The common thread: append-heavy writes, time as the primary query axis, and a need for built-in retention and windowed aggregation.

FAQ

Can I use InfluxDB on the Layerbase free tier?

No. InfluxDB is classed as a Performance engine, which means it stays always-on rather than sleeping when idle, and that puts it on the Pro plan. A metrics database that sleeps is not much use anyway, since the writes never stop. The local CLI instance is free if you are only evaluating.

How do I connect and authenticate?

Locally, lbase url influx1 gives you the URL and there is no token: the CLI starts InfluxDB 3 Core with authentication off. On Cloud, the Quick Connect panel shows an https:// endpoint and an API token, which the client sends as Authorization: Token <token>.

Is this guide for InfluxDB 2.x or 3.x?

InfluxDB 3, tested against 3.10.5. That's what the Layerbase CLI and Layerbase Cloud provision. If you're on a 2.x instance, the write model here is the same but the queries are not: version 2 uses Flux, version 3 uses SQL and InfluxQL.

What happened to buckets, organizations, and Flux?

Buckets became databases and organizations went away. Flux is in maintenance mode and is not supported in InfluxDB 3, so from(bucket:) pipelines don't run there at all. The version 2 write endpoint /api/v2/write still works as a compatibility path, which is why upgrading usually breaks reads before it breaks writes.

Do I have to delete old metrics myself?

No. A database carries a retention period, and InfluxDB drops points past it for you. Set it with influxdb3 create database --retention-period 7d or influxdb3 update database --retention-period 30d. Pair that with a rollup job that writes coarser summaries into a longer-lived database, so the long-range dashboards keep working after the raw points expire.

Wrapping Up

Run the full script:

bash
npx tsx metrics.ts

Under 100 lines of real code. You generated application metrics, wrote them with the Point builder over the line protocol, queried them with SQL, ran windowed aggregations with date_bin, compared response times across endpoints, and rolled the raw data into summaries. That same pattern scales from 50 data points to billions.

The InfluxDB 3 documentation covers Telegraf integration, the full SQL and InfluxQL references, the Processing Engine, and the separate Explorer UI (version 3 Core has no built-in web console the way version 2 did).

To manage your local InfluxDB instance:

bash
lbase stop influx1     # Stop the server
lbase start influx1    # Start it again
lbase list             # See all your database instances

The Layerbase CLI supports 20+ engines, so you can run InfluxDB for metrics alongside PostgreSQL for your app and Redis for sessions, all from one CLI. Prefer a GUI? Layerbase Desktop is available for macOS.