Skip to content

10-minute quickstart

Get started with self-hosted TimescaleDB in about 10 minutes

This guide helps you run TimescaleDB locally, create your first hypertable with the columnstore enabled, write data to the columnstore, and see instant analytical query performance.

Prerequisites for this procedure

To follow these steps, you'll need:

  • Docker installed on your machine
  • 8GB RAM recommended
  • The psql client (included with PostgreSQL) or any PostgreSQL client like pgAdmin

Start TimescaleDB using one of these options.

The easiest way to get started:

Important

This script is intended for local development and testing only. Do not use it for production deployments. For production-ready installation options, see the TimescaleDB installation guide.

On Linux or Mac:

Terminal window
curl -sL https://tsdb.co/start-local | sh

This command:

  • Downloads and starts TimescaleDB, if not already downloaded.
  • Exposes PostgreSQL on port 6543, a non-standard port that avoids conflicts with other PostgreSQL instances on port 5432.
  • Automatically tunes settings for your environment using timescaledb-tune.
  • Sets up a persistent data volume.

Wait about 1 to 2 minutes for TimescaleDB to download and initialize.

Connect using psql:

Terminal window
psql -h localhost -p 6543 -U postgres
# When prompted, enter password: password

You should see the PostgreSQL prompt. Verify TimescaleDB is installed:

SELECT extname, extversion FROM pg_extension WHERE extname = 'timescaledb';

Expected output:

extname | extversion
-------------+------------
timescaledb | 2.x.x
Tips

Prefer a GUI? If you would rather use a graphical tool instead of the command line, you can download pgAdmin and connect to TimescaleDB using the same connection details (host: localhost, port: 6543, user: postgres, password: password).

Create a hypertable for IoT sensor data with the columnstore enabled:

-- Create a hypertable with automatic columnstore
CREATE TABLE sensor_data (
time TIMESTAMPTZ NOT NULL,
sensor_id TEXT NOT NULL,
temperature DOUBLE PRECISION,
humidity DOUBLE PRECISION,
pressure DOUBLE PRECISION
) WITH (
tsdb.hypertable
);

tsdb.hypertable converts this into a TimescaleDB hypertable.

See more:

Add some sample sensor readings:

-- Enable timing to see time to execute queries
\timing on
-- Insert sample data for multiple sensors
-- SET timescaledb.enable_direct_compress_insert = on to insert data directly to the columnstore (columnnar format for performance)
SET timescaledb.enable_direct_compress_insert = on;
INSERT INTO sensor_data (time, sensor_id, temperature, humidity, pressure)
SELECT
time,
'sensor_' || ((random() * 9)::int + 1),
20 + (random() * 15),
40 + (random() * 30),
1000 + (random() * 50)
FROM generate_series(
NOW() - INTERVAL '90 days',
NOW(),
INTERVAL '1 seconds'
) AS time;
-- Once data is inserted into the columnstore we optimize the order and structure
-- this compacts and orders the data in the chunks for optimal query performance and compression
DO $$
DECLARE ch TEXT;
BEGIN
FOR ch IN SELECT show_chunks('sensor_data') LOOP
CALL convert_to_columnstore(ch, recompress := true);
END LOOP;
END $$;

This generates ~7,776,001 readings across 10 sensors over the past 90 days.

Verify the data was inserted:

SELECT COUNT(*) FROM sensor_data;

Now run some analytical queries that showcase TimescaleDB's performance:

-- Enable query timing to see performance
\timing on
-- Query 1: Average readings per sensor over the last 7 days
SELECT
sensor_id,
COUNT(*) as readings,
ROUND(AVG(temperature)::numeric, 2) as avg_temp,
ROUND(AVG(humidity)::numeric, 2) as avg_humidity,
ROUND(AVG(pressure)::numeric, 2) as avg_pressure
FROM sensor_data
WHERE time > NOW() - INTERVAL '7 days'
GROUP BY sensor_id
ORDER BY sensor_id;
-- Query 2: Hourly averages using time_bucket
-- Time buckets enable you to aggregate data in hypertables by time interval and calculate summary values.
SELECT
time_bucket('1 hour', time) AS hour,
sensor_id,
ROUND(AVG(temperature)::numeric, 2) as avg_temp,
ROUND(AVG(humidity)::numeric, 2) as avg_humidity
FROM sensor_data
WHERE time > NOW() - INTERVAL '24 hours'
GROUP BY hour, sensor_id
ORDER BY hour DESC, sensor_id
LIMIT 20;
-- Query 3: Daily statistics across all sensors
SELECT
time_bucket('1 day', time) AS day,
COUNT(*) as total_readings,
ROUND(AVG(temperature)::numeric, 2) as avg_temp,
ROUND(MIN(temperature)::numeric, 2) as min_temp,
ROUND(MAX(temperature)::numeric, 2) as max_temp
FROM sensor_data
GROUP BY day
ORDER BY day DESC
LIMIT 10;
-- Query 4: Latest reading for each sensor
-- Highlights the value of Skipscan executing in under 100ms without skipscan it takes over 5sec
SELECT DISTINCT ON (sensor_id)
sensor_id,
time,
ROUND(temperature::numeric, 2) as temperature,
ROUND(humidity::numeric, 2) as humidity,
ROUND(pressure::numeric, 2) as pressure
FROM sensor_data
ORDER BY sensor_id, time DESC;

Notice how fast these analytical queries run, even with aggregations across millions of rows. This is the power of TimescaleDB's columnstore.

Now that you have TimescaleDB running locally, explore more: