tsibble, the tidyverse time series object, and the rules it enforces on your index
Tidy Temporal Data Frames and Tools
At a glance
- What is it?
- tsibble turns a data frame into a time series object with a declared index and key, then gives you the verbs that follow from that declaration: fill_gaps for missing observations, index_by plus summarise for calendar aggregation. The rules are simple and the payoff is that gaps and intervals stop being your problem, provided your data is actually regular.
- Who is it for?
- tsibble suits an R team already working in the tidyverse who has regular interval data and wants to stop writing gap handling and period aggregation by hand, especially if the same code also needs to work on grouped series. It does not suit event driven data with no common interval, a team standardised on zoo or xts, or a project that only needs forecasting and would rather depend on one modelling package than on a stack.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 18 days ago.
- What is it written in?
- Mainly R, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A tsibble is a data frame with a declared index and a declared key
tsibble is the tidyverse's answer to the awkward parts of time series in R. The package description calls it a data infrastructure for tidy temporal data with wrangling tools, and the framing in the documentation is that a tsibble is a data and model oriented object rather than a special class that hides your data from you.
The four rules that define it are short enough to hold in your head. Index is a variable with inherent ordering from past to present. Key is a set of variables that define observational units over time. Each observation should be uniquely identified by index and key together. And each observational unit should be measured at a common interval if it is regularly spaced.
That last rule is the one people argue about, and the rest of the package is really an enforcement mechanism for it. Once you have declared which column is the index and which columns form the key, the package can compute the interval, fill implicit gaps, and aggregate over calendar periods without you writing any of that logic.
The data structure is a tsibble, and the audience is anyone in R who has fought with zoo, xts or base R time series classes and wanted to keep using dplyr verbs. The homepage is tsibble.tidyverts.org, the licence is GPL-3.0, and the last push was on 2026-10-05 with the most recent release v1.2.0 dated 2026-02-09.
Coercing a plain data frame, and what the printed object tells you
The entry point is as_tsibble, and it needs you to declare the key and the index explicitly. The worked example uses the weather data from nycflights13, where time_hour holds the date-times and origin identifies the station:
r library(dplyr) library(tsibble) weather <- nycflights13::weather %>% select(origin, time_hour, temp, humid, precip) weather_tsbl <- as_tsibble(weather, key = origin, index = time_hour)
What you get back, and this matters more than the function call, is visible in the printed output the documentation includes. The object reports itself as a tsibble of 26,115 rows and 5 columns, at interval 1h, in the America/New_York time zone, with a key of origin across 3 values. The columns carry their types, so origin is a character, time_hour is a dttm, and temp, humid and precip are doubles.
The interval and the time zone are not decoration. The interval is computed from the index based on its representation, and the documentation maps the common cases: annual from integer or double, quarterly from yearquarter, monthly from yearmonth, weekly from yearweek, daily from Date or difftime, and subdaily from POSIXt, difftime or hms. The time zone matters because a DST transition in a POSIXct column silently changes the length of a day, and having the zone printed in the header is how you notice that it happened.
The key may be empty, one variable, or several, and the full set of supported index classes is listed in the package help pages.
fill_gaps turns implicit missing values into explicit ones
Regular time series data is rarely regular. A station goes offline for an hour, a sensor drops a reading, and what you get back is a time series with holes that you cannot see by looking at the rows.
fill_gaps is the function that makes those holes visible and then fills them. The example fills the precipitation column with 0 and then carries the previous observation forward for temperature and humidity:
r full_weather <- weather_tsbl %>% fill_gaps(precip = 0) %>% group_by_key() %>% tidyr::fill(temp, humid, .direction = "down")
The printed result shows the arithmetic of what happened. The original object was 26,115 rows and the filled one is 26,190 rows, so 75 rows were inserted to complete the hourly grid for the three origins, and the result is now grouped by origin. The grouping is not cosmetic: fill() from tidyr replaces NA values with the previous observation for each origin, and that only means something within a series, so the data has to be grouped by key first.
The order of the two steps is the lesson. fill_gaps inserts the rows that were missing, and only then can you forward fill the values across them. The alternative order would have filled nothing.
The function also handles filling in time gaps by values or by functions, and the documentation states that it respects time zones for date-times. A vignette on implicit missing values covers the topic in more depth.
index_by and summarise for calendar period aggregation
The second workhorse is index_by, which the documentation describes as the counterpart of group_by in a temporal context, with the difference that it groups the index only rather than the key variables. Paired with summarise, it collapses rows into calendar periods.
r full_weather %>% group_by_key() %>% index_by(year_month = ~ yearmonth(.)) %>% # monthly aggregates summarise( avg_temp = mean(temp, na.rm = TRUE), ttl_precip = sum(precip, na.rm = TRUE) )
The mechanics are worth spelling out. index_by takes a new index, here year_month assigned from the yearmonth() function applied to the dot placeholder, and the dot refers to the current index variable. The summarise call then computes the mean temperature and the total precipitation over each monthly bucket.
The output shows the transformation clearly. The result is a tsibble of 36 rows and 4 columns at interval 1M, and the new index column year_month is typed as mth, so the monthly structure is carried in the class rather than left as text. The key is still origin, and the print output lists the first five months of 2013 for EWR with the mean temperature and the summed precipitation.
The documentation also points out that when collapsing rows, group_by and index_by take care of updating the key and the index respectively, so the metadata stays consistent with the new shape. And it notes that this combination can help with regularising a tsibble that had irregular time spacing in the first place, which is the same problem fill_gaps addresses from the other direction.
Where tsibble is the wrong tool
The first wrong case is irregular observation times. The interval concept assumes a common measurement frequency, and the key plus index pair is designed around it. Data recorded whenever an event happened, such as transactions or sensor triggers, fits the tidyverse approach but not this one, because there is no interval to compute and no regular grid to fill.
The second wrong case is very long series with many groups, where the object and its metadata are more than you need. A tsibble carries index, key, interval and grouping state, and that is real bookkeeping to maintain on a table with millions of rows and thousands of series.
The third wrong case is a workflow that needs a modelling tool rather than a data structure. tsibble gives you the object; the forecasting comes from the packages built on it, and if what you actually need is an ARIMA fit or an ETS fit, you are depending on a chain of packages rather than one.
The fourth wrong case is a team that has standardised on base R time series or on zoo and xts. Those classes are still there and work fine, and the migration cost of converting a codebase to a different mental model is real.
The fifth wrong case is expecting a lightweight dependency. The package is part of a wider ecosystem, with vignettes, pkgdown documentation and a revdep/ directory in the repository for reverse dependency checks, so pulling it in pulls in a stack of tidyverse conventions whether you want them or not.
The tidyverts ecosystem and what tsibble deliberately leaves out
tsibble is the foundation of a wider group of packages, and the documentation describes an ecosystem built around the tsibble object for tidy time series analysis.
The three named packages divide the work neatly. tsibbledata curates a range of tsibble data examples to explore the object. feasts provides support for visualising the data and extracting time series features. fable provides common forecasting methods for tsibble such as ARIMA and ETS, and fabletools, which fable is built upon, lays the modelling infrastructure to ease programming with tsibble.
The division explains what tsibble itself does not do. It does not forecast, it does not plot, and it does not extract features. It is a data structure with wrangling verbs, and everything above it in the stack is a separate package with its own release cycle and its own version to track.
For a reader deciding whether to adopt it, that boundary is the useful part. If your need is a tidy data frame that knows its own time structure, tsibble is the whole answer. If your need is forecasting, you are adopting tsibble plus fable plus fabletools, and each of those brings its own upgrade path.
The repository structure supports the same picture. There is a data/ directory and a data-raw/ directory for the bundled example datasets, a vignettes/ directory for the long form documentation, a hex/ directory for the package logo, and a revdep/ directory, which is where reverse dependency checks are recorded.
Package development, release cadence and what the README is generated from
This is a package built for a release cycle rather than a script, and the repository shows the machinery. The top level entries include DESCRIPTION and NAMESPACE for the package metadata and exports, a NEWS.md for the changelog, a CRAN-RELEASE file, cran-comments.md, a Makefile, a pkgdown/ directory and a _pkgdown.yml configuration, and tests/ for the test suite.
The Makefile holds the routine development tasks, each one a call to devtools:
bash test: Rscript -e "devtools::test()"
check: Rscript -e "devtools::check()"
Two entries are worth reading closely. The readme target renders README.Rmd with rmarkdown, which matches the comment at the very top of the generated README telling you that it is generated and that you should edit README.Rmd instead. Every example in the README, including the printed outputs, is therefore produced by running the code rather than pasted by hand, which is a good reason to trust the numbers in it.
On cadence, the release history is uneven in a way worth knowing before you plan around it. v1.2.0 was released on 2026-02-09, and before that v0.9.0 dates from 2020-06-10 and v0.8.3 from 2019-07-29. The repository is not archived and the last push was on 2026-10-05, so work is landing between releases, but the tags tell you that a year and a half can pass without a new CRAN version, and the CRAN status badge is the place to check what is currently published.
The licence is GPL-3.0, with the licence text in LICENSE.md.
Editorial conclusion
tsibble suits an R team already working in the tidyverse who has regular interval data and wants to stop writing gap handling and period aggregation by hand, especially if the same code also needs to work on grouped series. It does not suit event driven data with no common interval, a team standardised on zoo or xts, or a project that only needs forecasting and would rather depend on one modelling package than on a stack. Before adopting it, coerce one real series with as_tsibble and read the printed header, since the interval and the time zone printed there are the two facts that decide whether the rest of the package applies to your data, then check the CRAN status badge against the release you would pin, because v1.2.0 from 2026-02-09 is the most recent published version.
Frequently asked questions
How do I install tsibble in R?
The stable version comes from CRAN with install.packages("tsibble"). For the development version the documentation shows remotes::install_github("tidyverts/tsibble"), with the remotes install line left commented out.
What is the difference between an index and a key in tsibble?
Index is the variable with inherent ordering from past to present, and key is the set of variables that define observational units over time. Together they identify each observation uniquely, and each observational unit is expected to be measured at a common interval if it is regularly spaced.
How do I fill missing gaps in a tsibble?
Use fill_gaps(), which turns implicit missingness into explicit rows and can fill gaps by values or functions while respecting time zones for date-times. The example fills precipitation with 0 and then uses tidyr::fill with .direction = "down" for temperature and humidity after group_by_key().
How do I aggregate a tsibble by month?
Combine index_by() with summarise(), assigning a new index such as year_month = ~ yearmonth(.) and then summarising the variables of interest. The documentation notes that group_by() and index_by() update the key and the index respectively when rows are collapsed.
Which packages build on tsibble for forecasting and features?
The documentation names feasts for visualising data and extracting time series features, fable for common forecasting methods such as ARIMA and ETS, and fabletools, which fable is built upon, for the modelling infrastructure. tsibbledata curates example tsibble datasets.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tidyverts-tsibble)Was this useful?