YC.EntityFrameworkCore.TigerData.TimescaleDB 1.1.0

dotnet add package YC.EntityFrameworkCore.TigerData.TimescaleDB --version 1.1.0
                    
NuGet\Install-Package YC.EntityFrameworkCore.TigerData.TimescaleDB -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="YC.EntityFrameworkCore.TigerData.TimescaleDB" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="YC.EntityFrameworkCore.TigerData.TimescaleDB" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="YC.EntityFrameworkCore.TigerData.TimescaleDB" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add YC.EntityFrameworkCore.TigerData.TimescaleDB --version 1.1.0
                    
#r "nuget: YC.EntityFrameworkCore.TigerData.TimescaleDB, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package YC.EntityFrameworkCore.TigerData.TimescaleDB@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=YC.EntityFrameworkCore.TigerData.TimescaleDB&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=YC.EntityFrameworkCore.TigerData.TimescaleDB&version=1.1.0
                    
Install as a Cake Tool

YC.EntityFrameworkCore.TigerData.TimescaleDB

Tests NuGet Downloads codecov Release Issues License: MIT

First-class TimescaleDB support for Entity Framework Core, layered on top of the Npgsql EF Core provider.

Configure hypertables, columnstore compression, continuous aggregates, retention/reorder policies and background jobs with the Fluent API or attributes — everything flows through standard EF Core migrations (snapshot-diff, fully bidirectional, no imperative commands). Query with TimescaleDB hyperfunctions (time_bucket, first/last, gapfilling, histograms, UUIDv7) directly from LINQ, and reverse-engineer existing schemas with dotnet ef dbcontext scaffold.

Requirements: EF Core 10, Npgsql.EntityFrameworkCore.PostgreSQL 10, TimescaleDB 2.23+. The modern declarative interface is used (create_hypertable, ALTER TABLE … SET (timescaledb.…)); there is no legacy fallback.

Install

One package — design-time support (migration code generation, scaffolding for dotnet ef) is included:

dotnet add package YC.EntityFrameworkCore.TigerData.TimescaleDB

Setup

Call UseTimescaleDb() after UseNpgsql(...):

services.AddDbContext<MetricsContext>(options => options
    .UseNpgsql(connectionString)
    .UseTimescaleDb());
Option Default Effect
o.CreateExtension(false) true When true, the first migration emits CREATE EXTENSION IF NOT EXISTS timescaledb;. Disable when the extension is provisioned out of band (e.g. managed cloud).
o.MigrateData(false) true Model-wide default for migration data operations. Per-entity WithMigrateData(...) overrides it.
o.RebuildData(false) true Model-wide default — forbid data-copying rebuilds across all entities. Per-entity WithRebuildData(...) overrides it.
o.AutoDecompress(false) true Model-wide default for chunk decompression on columnstore disable. Per-entity WithAutoDecompress(...) overrides it.
options.UseNpgsql(cs).UseTimescaleDb(o => o.RebuildData(false));   // disable risky rebuilds everywhere

Intervals

Every duration is expressed type-safely — never a raw string:

Form Use it for Example Becomes
TimeSpan Fixed durations (days, hours, minutes, seconds) TimeSpan.FromDays(7) INTERVAL '7 days'
(int value, Every unit) Calendar units a TimeSpan can't express (1, Every.Month) INTERVAL '1 month'
long (integer-time hypertables only) Raw size in the column's own unit 86_400 86400

Every values: Second, Minute, Hour, Day, Week, Month, Year. Use (int, Every) (or its attribute form) whenever you need Week, Month or Year — those are calendar intervals with no fixed TimeSpan.

Quick start

The same hypertable, configured two ways.

Fluent API:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Reading>(e =>
    {
        e.HasNoKey();                                   // raw time-series → keyless
        e.ToTable("readings");
        e.IsHypertable(x => x.Time, chunkInterval: TimeSpan.FromDays(1));
        e.HasSpacePartition(x => x.DeviceId, partitions: 4);
        e.HasColumnstore(cs => cs
            .SegmentBy(x => x.DeviceId)
            .OrderByDescending(x => x.Time));
        e.HasColumnstorePolicy(after: TimeSpan.FromDays(7));
        e.HasRetentionPolicy(dropAfter: TimeSpan.FromDays(90));
    });
}

Attributes (equivalent):

[Columnstore(CompressAfter = 7, CompressAfterUnit = Every.Day)]
[Retention(90, Every.Day)]
public class Reading
{
    [PartitionColumn(1, Every.Day)]      // declares the hypertable + chunk interval
    [OrderBy(0, Sort.Descending)]        // columnstore ordering
    public DateTimeOffset Time { get; set; }

    [SpacePartition(4)]
    [SegmentBy]                          // columnstore segment column
    public string DeviceId { get; set; } = null!;

    public double Value { get; set; }
}

There is no [Hypertable] attribute — the [PartitionColumn] marker is the hypertable declaration, so compression / retention / dimensions cannot be written without one.

Features

Every feature is documented in FEATURES.md with its Fluent/attribute syntax, defaults and allowable values. Click through:

Feature What it does
Hypertable Partition a table by time into chunks — the core TimescaleDB primitive.
Integer-time hypertable Partition by an integer column (epoch/sequence) with an integer-now function.
Space dimensions Hash (by_hash) or range (by_range) sub-partitioning on extra columns.
Tablespaces Spread chunks across disks/tablespaces, round-robin.
Chunk skipping Min/max range tracking to prune chunks at query time.
Columnstore Native compression with segment-by / order-by layout and sparse indexes.
Columnstore policy Auto-compress chunks older than a data age or creation age.
Retention policy Auto-drop chunks older than a data age or creation age.
Reorder policy Periodically reorder chunks by an index.
Continuous aggregates Incrementally-materialized rollups over a hypertable.
Refresh policy Schedule continuous-aggregate refreshes.
Hierarchical caggs A cagg built on another cagg, ordered automatically.
Background jobs Schedule custom stored procedures via add_job.
Migration options Toggle the automatic data ops (migrate / rebuild / decompress).
Hyperfunctions in LINQ time_bucket, gapfill, first/last, histogram, UUIDv7.

Migrations — snapshot-driven, no special commands

dotnet ef migrations add records the TimescaleDB configuration as annotations on the table, plus migrationBuilder.Sql(...) for the objects that aren't tables (the extension, continuous aggregates, jobs, reorder policies). There are no imperative commands like ConvertToHypertable() or DisableColumnstore().

The provider's SQL generator turns the annotation delta into real DDL when the migration runs. Because the annotations carry both old and new values, every change is bidirectional automatically — the Down migration emits the exact reverse with no extra code, and re-running migrations add on an unchanged model produces an empty migration.

Transition matrix

Changes TimescaleDB cannot apply in place rebuild the table (CREATE TABLE (LIKE … INCLUDING ALL), copy every row, drop, rename) so data is preserved — nothing is rejected:

Change in the model Behavior
New table as hypertable CREATE TABLE … then create_hypertable(...)
Existing table → hypertable create_hypertable(..., migrate_data => true)
Hypertable → plain table rebuild → plain table, data copied back
Partition column changed rebuild → hypertable with the new column
Chunk interval changed set_chunk_time_interval(...) (future chunks)
Space dimension added add_dimension(by_hash(...))
Space dimension removed / changed rebuild
Range dimension added add_dimension(by_range(...))
Range dimension removed / changed rebuild
Columnstore enabled ALTER TABLE … SET (timescaledb.enable_columnstore, …)
Columnstore disabled every compressed chunk decompressed, then disabled
segmentby / orderby changed ALTER TABLE … SET (...) (future chunks)
Retention / columnstore / reorder policy ± add_*_policy / remove_*_policy
Reorder policy ± emitted after CREATE INDEX (add) / before drop (remove)
Chunk skipping ± SET timescaledb.enable_chunk_skipping = on; enable/disable_chunk_skipping
Cagg query changed drop + recreate (+ policies re-added, dependents cascaded)

The automatic, data-heavy steps (migrate_data, the rebuild row-copy, columnstore decompression) can be toggled per entity or model-wide — see Migration options.

Scaffolding

dotnet ef dbcontext scaffold reverse-engineers hypertables, space dimensions, columnstore settings, retention/ columnstore/reorder policies, chunk skipping, tablespaces and custom jobs. Continuous aggregates are not reverse-engineered (materialized views are outside the Npgsql scaffolding surface). Columnstore sparse indexes, creation-time retention/columnstore policies (drop_created_before / created_before) and range (by_range) dimensions are also not yet reverse-engineered from an existing database — configure them in the model.

Notes and limitations

  • Primary keys on hypertables must include the partition column (TimescaleDB requires every unique constraint to cover the partitioning columns; validated at model-build time).
  • Rebuilds are data-heavy and not free of caveats. Un-converting a hypertable, repartitioning, or changing a space dimension copies every row under lock via CREATE TABLE (LIKE … INCLUDING ALL). PostgreSQL LIKE does not copy FOREIGN KEY constraints (inbound or outbound) and recreates indexes under generated names; the migration includes a warning comment. Re-create FKs and any reorder policy manually afterward.
  • Chunk interval changes apply to future chunks only (set_chunk_time_interval); existing chunks keep their interval. Re-chunking historical data is intentionally not performed.
  • Chunk exclusion is automatic on the partition columns — filtering on the time column or a space dimension prunes chunks with no configuration. Chunk skipping (HasChunkSkipping) is the opt-in extension to a non-partition column, and only speeds up compressed chunks (the min/max is gathered when a chunk is converted to the columnstore — enable the columnstore too). Supported types: integer family + date/timestamp/timestamptz. The migration enables the timescaledb.enable_chunk_skipping GUC for you.
  • Converting an existing table to a hypertable and disabling the columnstore are data-heavy (row migration / chunk decompression); review the generated migration before running it in production.
  • Enabling the columnstore auto-creates a default conversion policy; HasColumnstorePolicy replaces it.
  • Direct Compress (Direct-to-Columnstore) is a session-level ingestion GUC (SET timescaledb.enable_direct_compress_insert/copy = on), not a table option — enable it in the session doing the bulk INSERT/COPY. It has no declarative DDL form, so it is outside this package's migration scope (and is a TimescaleDB tech preview).

Building & testing

Prerequisites: the .NET 10 SDK (see global.json) and Docker (the functional tests spin up a real TimescaleDB via Testcontainers).

dotnet build YC.EntityFrameworkCore.TigerData.TimescaleDB.slnx -c Release

# Fast SQL-generation / model tests (no Docker):
dotnet test test/YC.EntityFrameworkCore.TigerData.TimescaleDB.UnitTests

# End-to-end tests against a real TimescaleDB (Docker required):
dotnet test test/YC.EntityFrameworkCore.TigerData.TimescaleDB.FunctionalTests

The build treats warnings as errors and runs the .NET analyzers — keep it clean.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md first.

  • Issues use templates — pick Bug report or Feature request; they apply the right label automatically. Questions go to Discussions.
  • Pull requests follow the template and Conventional Commits in the PR title (feat:, fix:, docs:, …) — this drives versioning and the changelog.
  • Releases are automated: Release Please opens a release PR; merging it tags the version, writes CHANGELOG.md, and publishes to NuGet via OIDC (no API keys).
  • Security issues: see SECURITY.md — do not open a public issue.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 99 7/2/2026
1.0.1 109 6/15/2026
1.0.0 106 6/14/2026