Life is an Adventure
— Your Database Shouldn’t Be

RavenDB
    from Orders
    where State in ("ReadyToShip", "Shipped", "Delivered")
    and Date between $lastWeek and $today
    and search(Items[].Product, "bananas or apples")
    and Total > 1000
    order by OrderedAt desc
    limit 5
  • Stable, scalable, and secure by default

    Real time replication & automatic failover handling. Horizontal scalability. Encryption in transit & at rest.
    It Just Works.

  • Built for developers first

    Idiomatic SDKs, simple querying. Built-in Studio for monitoring & administration. Transactional NoSQL & ACID. Document-based, native time series support. Easy integration.

  • So predictable

    Familiar SQL-like query language, scalable aggregations, on-the-fly schema changes, intuitive APIs and 100s other small things that make a big difference.

  • Highly performant, efficient

    1 million reads and 150k writes/second per node on commodity hardware. Automatic indexing makes all queries fast. Your systems will be fast without complexity or effort.

Used in production by 1000+ customers

Toyota
trackmatic
upapp
Verizon
Rakuten Kobo
JetBrains
Capgemini
Medicaid
Insight
Particular
ESO
Configit
Luware
Nimble
Incomm Incentives
Simple Store
Serverflex
Sparkling Logic
esignatur
View.DO
Starnet
Strife
Amberwood Trading

Full Table Scan is the #1 enemy for each backend developer. With RavenDB, you cannot go wrong. There is no possibility to perform a query without an index.

It doesn’t mean that you need to create and index for each query in your application! RavenDB learn from your application behaviour and will create auto indexes for you. RavenDB will create the optimal set of indexes to cover your application needs.

Being Boring means that you can sleep at night instead of waiting for the next Full Table Scan nightmare to happen.

// New index will be created
from Companies
where Name = "Island Trading"

// Previous index will get merged with new one
from Companies
where Address.Country = "UK"

// I still have one index, but all three queries can be handled by it
// Amazing!
from Companies
where Phone = "(171) 555-0297"
// New index will be created
List<Company> companies1 = session.Query<Company>()
    .Where(x => x.Name == "Island Trading")
    .ToList();

// Previous index will get merged with new one
List<Company> companies2 = session.Query<Company>()
    .Where(x => x.Address.Country == "UK")
    .ToList();

// I still have one index, but all three queries
// can be handled by it
// Amazing!
List<Company> companies3 = session.Query<Company>()
    .Where(x => x.Phone == "(171) 555-0297")
    .ToList();
# New index will be created
companies1 = list(
    session.query(object_type=Company).where_equals("name", "Island Trading")
)

# Previous index will get merged with new one
companies2 = list(
    session.query(object_type=Company).where_equals("address.country", "UK")
)

# I still have one index, but all three queries can be handled by it
# Amazing !
companies3 = list(
    session.query(object_type=Company).where_equals("phone", "(171) 555-0297")
)
// New index will be created
List < Company > companies1 = session.query(Company.class)
  .whereEquals("Name", "Island Trading")
  .toList();

// Previous index will get merged with new one
List < Company > companies2 = session.query(Company.class)
  .whereEquals("Address.Country", "UK")
  .toList();

// I still have one index, but all three queries can be handled by it
// Amazing!
List < Company > companies3 = session.query(Company.class)
  .whereEquals("Phone", "(171) 555-0297")
  .toList();
// New index will be created
$companies1 = $session->query(Company::class)
    ->whereEquals("Name", "Island Trading")
    ->toList();

// Previous index will get merged with new one
$companies2 = $session->query(Company::class)
    ->whereEquals("Address.Country", "UK")
    ->toList();

// I still have one index, but all three queries can be handled by it
// Amazing!
$companies3 = $session->query(Company::class)
    ->whereEquals("Phone", "(171) 555-0297")
    ->toList();
const companies1: Company[] = await session.query(Company)
	.whereEquals("Name", "Island Trading")
	.all();

// Previous index will get merged with new one
const companies2: Company[] = await session.query(Company)
	.whereEquals("Address.Country", "UK")
	.all();

// I still have one index, but all three queries can be handled by it
// Amazing!
const companies3: Company[] = await session.query(Company)
	.whereEquals("Phone", "(171) 555-0297")
	.all();
// New index will be created
var companies1 []*Company
err = session.QueryCollectionForType(reflect.TypeOf(&Company{})).
    WhereEquals("Name", "Island Trading").
    GetResults(&companies1)

// Previous index will get merged with new one
var companies2 []*Company
err = session.QueryCollectionForType(reflect.TypeOf(&Company{})).
    WhereEquals("Address.Country", "UK").
    GetResults(&companies2)

// I still have one index, but all three queries can be handled by it
// Amazing!
var companies3 []*Company
err = session.QueryCollectionForType(reflect.TypeOf(&Company{})).
    WhereEquals("Phone", "(171) 555-0297").
    GetResults(&companies3)

Use time-series in your next finance, IoT, or healthcare application, where chronological order of data points is crucial for trend analysis. anomaly detection, and predictive modelling.

Take advantage of:

  • Incremental time-series which avoids conflicts and a cost of synchronization for real-time updates.
  • Built-in RQL support for data extraction.
  • Indexing capabilities for advanced querying scenarios.
  • Rollup and retention for data aggregation and cleanup.
from Companies
    where id() = 'companies/55-A'
    select timeseries(
        from StockPrices
        between '2020-01-01' and '2020-06-30' 
        group by '1 month'
        select min(), max()
    ) as StockPrices
var stocks =
    session.TimeSeriesFor("companies/55-A")
        .Get(from
             : new DateTime(2020, 1, 1), to
             : new DateTime(2020, 6, 30))
        .GroupBy(g => g.Timestamp.Month)
        .Select(g => new {Month = g.Key, Min = g.Min(x => x.Value.Close),
                          Max = g.Max(x => x.Value.Close)})
        .ToList();
from itertools import groupby

with self.store.open_session() as session:
    stocks = session.typed_time_series_for(StockPrice, "users/karmel").get()
    grouped_stocks = groupby(stocks, key=lambda x: x.timestamp.month)

    def get_min_max(group):
        values = [x for x in group]
        close_values = [x.value.close for x in values]
        return {
            "Month": values[0].timestamp.month,
            "Min": min(close_values),
            "Max": max(close_values),
        }

    stocks = [get_min_max(group) for _, group in grouped_stocks]
IRawDocumentQuery<StockPrice> stocks = session.advanced()
    .rawQuery(StockPrice.class, """
from Companies
where id() = 'companies/55-A'
select timeseries(
        from StockPrices
        between '2020-01-01' and '2020-06-30' 
        group by '1 month'
        select min(), max()
) as StockPrices
""");
$query = <<<EOQ
from Companies
where id() = 'companies/55-A'
select timeseries(
        from StockPrices
        between '2020-01-01' and '2020-06-30' 
        group by '1 month'
        select min(), max()
) as StockPrices
EOQ;
    
$stocks = $session -> advanced() -> rawQuery(StockPrice:: class, $query);
const stocks: StockPrice[] = await session.advanced
    .rawQuery(
`from Companies
where id() = 'companies/55-A'
select timeseries(
        from StockPrices
        between '2020-01-01' and '2020-06-30' 
        group by '1 month'
        select min(), max()
) as StockPrices`,
     StockPrice).all();

Are you looking for a place to eat, or maybe a nearby taxi?
Or are you just browsing through some online stores?

Our built-in Spatial and Faceted Search support can help you achieve this, with a vast set of supported standards like WKT for Spatial or range aggregations for Facets.

All of that is integrated into our RQL querying language.

// Find all Employees in a 20km circle from 47.623473, -122.3060097 coordinates
from Employees
where spatial.within(
    spatial.point(Address.Location.Latitude, Address.Location.Longitude),
    spatial.circle(20, 47.623473, -122.3060097)

// Return facets aggregated by
// - Brand
// - Five Ranges
from index "Cameras/ByFeatures"
select facet(Brand,
           sum(UnitsInStock), avg(Price), min(Price), max(MegaPixels)),
       facet(Price < 200.0,
            Price >= 200.0 and Price < 400.0,
            Price >= 400.0 and Price < 600.0,
            Price >= 600.0 and Price < 800.0,
            Price >= 800.0,
            sum(UnitsInStock), avg(Price), min(Price), max(MegaPixels))
// Find all Employees in a 20km circle from 47.623473, -122.3060097 coordinates
List<Employee> employees =
    session.Query<Employee>()
        .Spatial(
            factory => factory.Point(
                x => x.Address.Location.Latitude,
                x => x.Address.Location.Longitude),
            factory => factory.WithinRadius(20, 47.623473, - 122.3060097)
        ).ToList();

// Return facets aggregated by
// - Brand
// - Five Ranges
Dictionary<string, FacetResult> results = session.Query<Camera>("Cameras/ByFeatures")
    .AggregateBy(f => f
        .ByField(c => c.Brand)
        .SumOn(c => c.UnitsInStock).AverageOn(c => c.Price).MinOn(c => c.Price).MaxOn(c => c.MegaPixels))
    .AndAggregateBy(f => f.ByRanges(
            range => range.Price < 200.0,
            range => range.Price >= 200.0 && range.Price < 400.0,
            range => range.Price >= 400.0 && range.Price < 600.0,
            range => range.Price >= 600.0 && range.Price < 800.0,
            range => range.Price >= 800.0
        )
        .SumOn(c => c.UnitsInStock).AverageOn(c => c.Price).MinOn(c => c.Price).MaxOn(c => c.MegaPixels))
    .Execute();
#  Find all Employees in a 20km circle from 47.623473, -122.3060097 coordinates
employees = list(
    session.query(object_type=Employee).spatial(
        PointField("address.location.latitude", "address.location.longitude"),
        lambda f: f.within_radius(20, 47.623473, -122.3060097),
    )
)

# Return facets aggregated by
# - Brand
# - Five Ranges

range = RangeBuilder.for_path("price")
product_aggregations = (
    session.query_index("Cameras/ByFeatures")
    .aggregate_by(
        lambda f: f.by_field("brand")
        .sum_on("units_in_stock").average_on("price").min_on("price").max_on("mega_pixels")
    )
    .and_aggregate_by(
        lambda f: f.by_ranges(
            range.is_less_than(200),
            range.is_greater_than_or_equal_to(200).is_less_than(400),
            range.is_greater_than_or_equal_to(400).is_less_than(600),
            range.is_greater_than_or_equal_to(600).is_less_than(800),
            range.is_greater_than_or_equal_to(800),
        )
        .sum_on("units_in_stock").average_on("price").min_on("price").max_on("mega_pixels")
    )
    .execute()
)
// Find all Employees in a 20km circle from 47.623473, -122.3060097 coordinates
List<Employee> query = session.query(Employee.class)
    .spatial(
    new PointField("Address.Location.Latitude", "Address.Location.Longitude"),
    f -> f.withinRadius(20, 47.623473, -122.3060097))
    .toList();

// Return facets aggregated by
// - Brand
// - Five Ranges
RangeBuilder<Integer> range = new RangeBuilder<>("price");
Map<String, FacetResult> results = session.query(Object.class, Query.index("Cameras/ByFeatures"))
    .aggregateBy(f -> f
    .byField("brand")
    .sumOn("units_in_stock").averageOn("price").minOn("price").maxOn("mega_pixels"))
    .andAggregateBy(f -> f.byRanges(
        range.isLessThan(200),
        range.isGreaterThanOrEqualTo(200).isLessThan(400),
        range.isGreaterThanOrEqualTo(400).isLessThan(600),
        range.isGreaterThanOrEqualTo(600).isLessThan(800),
        range.isGreaterThanOrEqualTo(800)
    )
    .sumOn("units_in_stock").averageOn("price").minOn("price").maxOn("mega_pixels"))
    .execute();
// Find all Employees in a 20km circle from 47.623473, -122.3060097 coordinates
$query = $session->query(Employee::class)
    ->spatial(
        new PointField("Address.Location.Latitude", "Address.Location.Longitude"),
        function($f) { return $f->withinRadius(20, 47.623473, -122.3060097); }
    )
    ->toList();

// Return facets aggregated by
// - Brand
// - Five Ranges
/** @var array  $results */
$range = new RangeBuilder("price");
$results = $session->query(null, Query::index("Cameras/ByFeatures"))
    ->aggregateBy(function($f) {
        return $f
            ->byField("brand")
            ->sumOn("units_in_stock")->averageOn("price")->minOn("price")->maxOn("mega_pixels");
    })
    ->spatial("LocationCoordinates", )
    ->andAggregateBy(function($f) use ($range) { return
            $f->byRanges(
                $range->isLessThan(200),
                $range->isGreaterThanOrEqualTo(200)->isLessThan(400),
                $range->isGreaterThanOrEqualTo(400)->isLessThan(600),
                $range->isGreaterThanOrEqualTo(600)->isLessThan(800),
                $range->isGreaterThanOrEqualTo(800)
            )
            ->sumOn("units_in_stock")->averageOn("price")->minOn("price")->maxOn("mega_pixels");
    })
    ->execute();
// Find all Employees in a 20km circle from 47.623473, -122.3060097 coordinates
const query: Employee[] = await session.query(Employee)
    .spatial(new PointField("Address.Location.Latitude", "Address.Location.Longitude"),
        f => f.withinRadius(20, 47.623473, -122.3060097))
    .all();

// Return facets aggregated by
// - Brand
// - Five Ranges

const range = new RangeBuilder("price");
const results: Map < string, FacetResult > = await session.query({
        indexName: "Cameras/ByFeatures"
    })
    .aggregateBy(f => f
        .byField("brand")
        .sumOn("units_in_stock").averageOn("price").minOn("price").maxOn("mega_pixels"))
    .andAggregateBy(f => f
        .byRanges(
            range.isLessThan(200),
            range.isGreaterThanOrEqualTo(200).isLessThan(400),
            range.isGreaterThanOrEqualTo(400).isLessThan(600),
            range.isGreaterThanOrEqualTo(600).isLessThan(800),
            range.isGreaterThanOrEqualTo(800)
        )
        .sumOn("units_in_stock").averageOn("price").minOn("price").maxOn("mega_pixels"))
    .execute();

Writing a piece of code that reliably process data in a distributed environment is a cumbersome and non-trivial task. With our Data Subscriptions, RavenDB takes care of all the heavy lifting and guarantees that every single item will be processed without any additional infrastructure.

Why waste time maintaining the code, when you can just subscribe to an RQL-based subscription and focus on the business code.

// Create
var name = await DocumentStore.Subscriptions.CreateAsync();

// Open
var worker = DocumentStore.Subscriptions.GetSubscriptionWorker(name);

// Subscribe
_ = worker.Run(batch =>
{
    // Issue an Invoice or Send an Email
});
# Create
name = self.store.subscriptions.create_for_class(Order)

# Open
worker = self.store.subscriptions.get_subscription_worker(SubscriptionWorkerOptions(name), Order)

# Subscribe
def _do_work(batch: SubscriptionBatch):
    with batch.open_session() as session:
        for item in batch.items:
            order = item.result
                
            # Issue an Invoice, Send an Email
                
            order.shipped_at = datetime.now()
                
            session.save_changes()

worker.run(_do_work)
// Create
SubscriptionCreationOptions subscriptionCreationOptions = new SubscriptionCreationOptions();
subscriptionCreationOptions.setQuery("from Orders where ShippedAt is null");
String name = documentStore.subscriptions().create(subscriptionCreationOptions);

// Open
SubscriptionWorker < Order > worker = documentStore.subscriptions().getSubscriptionWorker(Order.class, name);

// Subscribe
worker.run(batch -> {
    try (IDocumentSession session = batch.openSession()) {
        for (SubscriptionBatchBase.Item < Order > item: batch.getItems()) {
            Order result = item.getResult();

            // Issue an Invoice, Send an Email

            result.setShippedAt(new Date());
            session.saveChanges();
        }
    }
});
// Create
const subscriptionCreationOptions: SubscriptionCreationOptions = {
    query: "from Orders where ShippedAt is null"
};
const name = await documentStore.subscriptions.create(subscriptionCreationOptions);

// Open
const worker = documentStore.subscriptions.getSubscriptionWorker({
    documentType: Order,
    subscriptionName: name
});

// Subscribe
worker.on("batch", async (batch, callback) => {
    const session = batch.openSession();
    try {
        for (const item: Item of batch.items) {
            const result: Order = item.result;

            // Issue an Invoice, Send an Email

            result.shippedAt = new Date();
            await session.saveChanges();
        }
    } finally {
        session.dispose();
    }
    callback();
});

Creating a voting or pooling system can be challenging due to the synchronization and aggregation issues involved. We are simplifying this process to just a few lines of code and taking the heavy burden on ourselves.

With counters in a distributed environment, you can consume a tremendous amount of data in a short time span and still enjoy the final results in a swift manner.

// Vote
var counters = session.CountersFor("candidate/1");
counters.Increment("Votes");
session.SaveChanges();

// Check results
var counters = session.CountersFor("candidate/1");
var votes = counters.Get("Votes");
# Vote
counters = session.counters_for("candidate/1")
counters.increment("Votes")
session.save_changes()

# Check results
counters = session.counters_for("candidate/1")
votes = counters.get("Votes")
// Vote
ISessionDocumentCounters counters = session.countersFor("candidate/1");
counters.increment("Votes");
session.saveChanges();

// Check results
ISessionDocumentCounters counters = session.countersFor("candidate/1");
Long votes = counters.get("Votes");
// Vote
$counters = $session->countersFor("candidate/1");
$counters->increment("Votes");
$session->saveChanges();

// Check results
$counters = $session->countersFor("candidate/1");
$votes = $counters->get("Votes");
// Vote
const counters = session.countersFor("candidate/1");
counters.increment("Votes");
await session.saveChanges();

// Check results
const counters = session.countersFor("candidate/1");
const votes: number = await counters.get("Votes");
Reviews

Valued by customers

Highly rated on Gartner

RavenDB is one of the highest rated solutions in the Cloud Database Management Systems category.

Top Rated DBaaS

RavenDB has been repeatedly awarded one of the best DBaaS solutions by TrustRadius.

“As a document database it remains true to the core principles of these type of storage mechanisms. Somehow it managed to combine the best of relational databases with that of document databases.”
Hadi Hariri
VP of Developer Advocacy
JetBrains
“Considering how huge the amount of data sent back and forth in a single quote document is, the fact that RavenDB can store the entire document and continue to perform well is really impressive.”
Peter Tiedeman
Senior Principal Software Developer
Configit
“We take pain away from our users, and RavenDB takes pain away from us.”
Alan Doherty
Co-Founder
Serverflex
“A document database without querying power would have become a bottleneck. RavenDB gave us the querying power we needed without sacrificing the flexibility in the documents.”
Carlos Serrano
Co-Founder and CTO
Sparkling Logic
“Databases are scary. They hold your data. If something goes wrong, you are in trouble. Knowing how RavenDB works internally gives me a sense of peace that if I get into trouble, I know exactly what to do.”
Sarmaad Amin
Co-Founder
Simple Store
“RavenDB does everything I need, and a million times more.”
Jeremy Holt
CEO
Amberwood Trading

Get started in minutes,
comfortable in days, master it in weeks.

RavenDB is explicitly meant to get out of your way. You should just write your system and not worry about persistence. With RavenDB there isn't a huge chasm of complexity to cross. The burden of running your database in production and under load is on RavenDB.

Enterprise-ready

Used in Production
by Fortune 500 Enterprises

Under load, RavenDB matches or exceeds Couchbase performance at the 99.99 percentile with third of the hardware resources. In the cloud this translates to 80% cost savings.

Trevor Hunter
CTO of Rakuten Kobo
AWS GCP Azure Marketplace

Deployed to millions of locations across the entire world

12000+ customers across multiple countries

15+ years on the market

  • ISO27001
  • SOC2 & SOC3
  • GDPR
  • HIPAA

The highest security and compliance standards

Resilient to failures

Mentioned in Gartner Forrester
Highly rated on Gartner Peer Insights Trust Radius
Toyota trackmatic upapp Verizon Rakuten Kobo JetBrains Capgemini Medicaid Particular Software Incomm Incentives ESO Configit
Use cases

Real stories of RavenDB’s impact

See how Rakuten Kobo kept their costs down without sacrificing performance

RavenDB has shown to deliver remarkable performance improvements and cost savings, as evidenced by Rakuten Kobo's experience where it led to significant infrastructure cost reduction.

Use Case

Deepening Configuration Capabilities

Explore how Configit harnesses the power of RavenDB to enhance the depth and efficiency of their configuration solutions.

See how other businesses improved their systems

Setup RavenDB now

We built a database that works for you,
instead of making you work.

We are open-source Star