DEV Community

Team Timescale for Timescale

Posted on • Originally published at timescale.com on

Connecting TypeScript and PostgreSQL: Timescale Integrations Expand

Today, we're excited to announce that we're expanding our ecosystem support to allow you to connect PostgreSQL and TypeScript, among other programming languages, when using TimescaleDB. While PostgreSQL has always been language-agnostic, we recognize that each developer community has unique needs, patterns, and expectations regarding database integration.

Better database integration streamlines data access, enhances performance, and improves scalability, so our mission is simple: meet developers where they are and make TimescaleDB a natural extension of their existing PostgreSQL workflow—regardless of their programming language of choice.

TypeScript is a strongly typed superset of JavaScript with excellent tooling support, static type checking, and enhanced development features. It provides enhanced developer experience through early error detection, superior code organization, and seamless integration with modern frameworks.

TypeScript's connection with PostgreSQL through TimescaleDB offers developers a type-safe, maintainable approach to building data-driven applications with enhanced tooling support, static type checking, and seamless integration with modern frameworks.

How to Connect TypeScript and PostgreSQL

Daniel Starns leads our TypeScript and PostgreSQL integration. He previously worked on the core of Prisma ORM. To build the timescaledb-ts package, Daniel implemented feature parity with the timescaledb-ruby features (learn more about the TimescaleDB Ruby gem here) but followed the TypeScript style. He implemented the TimescaleDB functionality in a core library that wraps SQL and extra packages for TypeORM and Sequelize.

Getting started with TypeORM and TimescaleDB is straightforward; simply install our integration alongside your TypeORM installation:

$ npm install typeorm @timescaledb/typeorm

Enter fullscreen mode Exit fullscreen mode

Then, you can use our custom TypeScript Decorators to annotate any common generic model:

import { Entity, PrimaryColumn } from 'typeorm';
+ import { Hypertable, TimeColumn } from '@timescaledb/typeorm';

+ @Hypertable({ ... })
@Entity('page_loads')
export class PageLoad {
  @PrimaryColumn({ type: 'varchar' })
  user_agent!: string;

+ @TimeColumn()
  time!: Date;
}
Enter fullscreen mode Exit fullscreen mode

_Copyable code snippet with our custom TypeScript Decorators._
Same code, with highlights: You can provide the highlighted code to TypeORM to connect to your TimescaleDB database.

The highlighted code above is what users need to provide to TypeORM to connect to TimescaleDB. The interaction behind the scenes handles the rest, such as auto-migrating hypertables.

There are several other expressive decorators, such as @ContinuousAggregate and @Rollup, that let you express and fine-tune aggregation views on top of time windows. If you find the TypeScript package helpful to connect to your PostgreSQL database, don’t forget to leave us a GitHub star! 🌟

To learn more, follow the guides in our source:

Outside of the engineering work, the TypeScript team has connected with the TypeORM maintainers. They have a pinned post on their Discord server and collaborated in a call with the maintainers. From here, the goal is to collaborate further with the community, create more documentation and examples, perform live streams, and educate developers through community events.

PostgreSQL Integrations: Ruby, PHP, and More

Beyond TypeScript, we've expanded our integration efforts to include several other languages. We began this journey with Ruby, creating a deeply integrated experience that feels natural to Ruby and Rails developers, including:

  • Native ActiveRecord extensions for TimescaleDB features
  • Simplified configuration and migration tooling
  • Performance optimization patterns tailored to Ruby applications
  • Comprehensive documentation with Ruby-specific examples

Building on this foundation, we've already expanded to PHP, thanks to Tobias Petry.

This approach isn't limited to specific languages—it establishes a blueprint for how TimescaleDB can integrate seamlessly with any language ecosystem through both official packages and community-led initiatives.

Let's examine the setup for each language:

  • TypeScript
  • Ruby
  • PHP

TypeScript Setup


import { Entity, PrimaryColumn } from 'typeorm';
import { Hypertable, TimeColumn } from '@timescaledb/typeorm';

@Entity('page_loads')
@Hypertable({
  compression: { // Optional compression
    compress: true,
    compress_orderby: 'time',
    compress_segmentby: 'user_agent',
    policy: {
      schedule_interval: '7 days',
    },
  },
})
export class PageLoad {
  @PrimaryColumn({ name: 'user_agent', type: 'varchar' })
  userAgent!: string;

  @TimeColumn()
  time!: Date;
}



hypertable_options = {
  time_column: 'created_at', # partition data by this column
  chunk_time_interval: '1 day', # create a new table for each day
  compress_segmentby: 'identifier', # columnar compression key
  compress_after: '7 days', # start compression after 7 days
  compress_orderby: 'created_at DESC', # compression order
  drop_after: '6 months' # delete data after 6 months
}

create_table(:events, id: false, hypertable: hypertable_options) do |t|
  t.timestamptz :created_at, null: false
  t.string :identifier, null: false
  t.jsonb :payload
end



return new class extends Migration
{
    public function up(): void
    {
        Schema::createExtensionIfNotExists('timescaledb');

        Schema::create('visits', function (Blueprint $table) {
            $table->identity();
            $table->bigInteger('website_id');
            $table->text('url');
            $table->float('duration');
            $table->timestampTz('created_at');

            $table->primary(['id', 'created_at']);
            $table->index(['website_id', 'created_at']);

            $table->timescale(
                new CreateHypertable('created_at', '1 day'),
                new CreateReorderPolicyByIndex('website_id', 'created_at'),
                new EnableCompression(segmentBy: 'website_id'),
                new CreateCompressionPolicy('3 days'),
                new CreateRetentionPolicy('1 year'),
                new EnableChunkSkipping('id'),
            );
        });

        Schema::continuousAggregate('visits_agg', function(CaggBlueprint $table) {
            $table->as("
                SELECT
                    time_bucket('1 hour', created_at) AS bucket,
                    website_id,
                    url,
                    SUM(duration) AS duration
                FROM visits
                GROUP BY bucket, website_id, url
            ");
            $table->realtime();
            $table->index(['website_id','url']);

            $table->timescale(
                new CreateRefreshPolicy('5 minutes', '1 days', '2 hours'),
                new EnableCompression(),
                new CreateCompressionPolicy('2 days'),
            );
        });
    }
};


Enter fullscreen mode Exit fullscreen mode

Ruby Setup

hypertable_options = {
  time_column: 'created_at',        # partition data by this column
  chunk_time_interval: '1 day',     # create a new table for each day
  compress_segmentby: 'identifier', # columnar compression key
  compress_after: '7 days',         # start compression after 7 days
  compress_orderby: 'created_at DESC', # compression order
  drop_after: '6 months'            # delete data after 6 months
}

create_table(:events, id: false, hypertable: hypertable_options) do |t|
  t.timestamptz :created_at, null: false
  t.string :identifier, null: false
  t.jsonb :payload
end
Enter fullscreen mode Exit fullscreen mode

PHP Setup

return new class extends Migration
{
    public function up(): void
    {
        Schema::createExtensionIfNotExists('timescaledb');

        Schema::create('visits', function (Blueprint $table) {
            $table->identity();
            $table->bigInteger('website_id');
            $table->text('url');
            $table->float('duration');
            $table->timestampTz('created_at');

            $table->primary(['id', 'created_at']);
            $table->index(['website_id', 'created_at']);

            $table->timescale(
                new CreateHypertable('created_at', '1 day'),
                new CreateReorderPolicyByIndex('website_id', 'created_at'),
                new EnableCompression(segmentBy: 'website_id'),
                new CreateCompressionPolicy('3 days'),
                new CreateRetentionPolicy('1 year'),
                new EnableChunkSkipping('id'),
            );
        });

        Schema::continuousAggregate('visits_agg', function(CaggBlueprint $table) {
            $table->as("
                SELECT
                    time_bucket('1 hour', created_at) AS bucket,
                    website_id,
                    url,
                    SUM(duration) AS duration
                FROM visits
                GROUP BY bucket, website_id, url
            ");
            $table->realtime();
            $table->index(['website_id','url']);

            $table->timescale(
                new CreateRefreshPolicy('5 minutes', '1 days', '2 hours'),
                new EnableCompression(),
                new CreateCompressionPolicy('2 days'),
            );
        });
    }
};
Enter fullscreen mode Exit fullscreen mode

Why Language-Specific Integrations Matter

While TimescaleDB works with any language that connects to PostgreSQL, we believe in going beyond basic compatibility. Language-specific integrations offer significant advantages:

  • Idiomatic implementations that align with community best practices
  • Enhanced developer experience through familiar patterns and tooling
  • Targeted performance optimizations for language-specific ORMs and drivers
  • Relevant documentation with contextual examples and use cases

Our goal isn't merely compatibility with your technology stack—we aim to become an essential, natural extension of it.

Want to create your own integration? Check out our comprehensive integration guide.

Join Us: We're Supporting Community Integrations

We're actively seeking developers interested in building and maintaining TimescaleDB integrations for their language communities. Whether you're passionate about Python, Go, Rust, PHP, JavaScript, Java, .NET, or any other ecosystem, we want to support your efforts.

Here's what we offer to community integration maintainers:

  • Dedicated technical support from our DevRel team
  • Co-marketing opportunities to showcase your integration
  • Collaborative documentation development
  • Conference and meetup sponsorship for community education
  • Early access to upcoming features

If you're interested, book a Technical Office Hours call with me (Jônatas, developer advocate at Timescale), and let's begin the conversation!

Real-World Impact: Performance Workshop Series

As part of this initiative, I presented "The PostgreSQL Performance Workshop for Rubyists" at a few conferences, including Tropical on Rails in São Paulo, Brazil. This workshop demonstrated our commitment to education across language communities, with content that is adaptable to other languages.

The workshops covered:

  • Advanced query optimization techniques
  • Effective time-series data modeling
  • Scaling strategies for high-throughput applications
  • PostgreSQL internals that impact application performance

To provide more educational resources, we're already bringing Ruby to our blog and showing the real-world impact of these integrations. Check out this article from an early developer adopter of the timescaledb gem on how to set up a dashboard for global energy data analytics.

Our Roadmap: What's Next

We're approaching this ecosystem expansion methodically. Throughout this process, you can expect to see us document our approach, share best practices, and create reusable patterns that make TimescaleDB integration consistent across languages while remaining idiomatic to each.

Community Engagement and Support

We're committed to fostering a strong community around TimescaleDB and encouraging broader ecosystem development. Here's how we plan to engage and support developers:

  • Open collaboration : We welcome developers to actively participate in shaping TimescaleDB integrations through ideas, expertise, and code contributions.
  • Community events : We'll host and participate in events and workshops to connect with developers and provide hands-on support.
  • Project sponsorship : We're sponsoring open-source projects that align with our mission of making time-series data accessible.
  • Developer support : Our team offers timely assistance to developers integrating TimescaleDB into their projects through dedicated Office Hours.

Through these initiatives, we aim to build an inclusive community where developers can learn, collaborate, and create innovative applications with TimescaleDB.

Get Involved

At Timescale, we believe real-time analytics is essential for any data-driven business, which means time-series data is everywhere. Developers across all language communities deserve high-quality tools for handling this demanding workload. By expanding our ecosystem support and embracing community-led integrations, we're creating a more inclusive and powerful platform.

Join us in this mission! Here’s how you can get involved:

  1. Join our community and connect with the Ecosystem team.
  2. Check out our integration development guidelines .
  3. Book a session with our technical team.

Are you building an integration for TimescaleDB in your preferred language? We'd love to hear about it! Share your project or reach out to our Ecosystem team directly.

Top comments (0)