Image of a network graph

Global database comparison

Looking at Deno KV, DynamoDB, Fauna, PlanetScale and Upstash Redis on Deno Deploy

By Chris Knight, 20/06/2023 (last updated 19/09/23)

Deno recently launched a new global database, KV. Is it any good? In this post, we'll explore KV and other globally distributed databases to see how KV stacks up and what the best options are for use in Deno Deploy, examining latencies, characteristics and ease of use for performing common database interactions.


Contents


 

Introduction

Before the cloud came along, a typical web application architecture would consist of a web server and a database. These typically were hosted in the same datacentre. This worked well for application teams (with everything in the same physical location), but not so well for users far away from the datacentre. The time it takes for data to travel a network, known as latency, for requests from the browser to the server could significantly impact the user experience.Traditional architecture diagramTo help solve this problem of users far away, a new concept arrived, sometimes referred to as Edge hosting, where your application would be served from multiple global locations with the user being served from the closest location. This solved one problem of long latencies between the user's browser and the server. However, ironically, this made the experience worse for some applications and users as all those server to database calls were still going back to the original datacentre which could be far away from the user leading to increased overall response times.Edge application architecture diagramThe next evolution in this journey are globally distributed databases, hosted in multiple regions around the world. By bringing the database closer to the user and server, both server and database are now closer to all your users around the globe and the latency for database calls can be significantly reduced. Other benefits include increased scalability as your traffic is split across many instances, as well as high availability with the ability to provide a database service even if one or more database nodes goes offline. Hooray! Problem solved right? Well, not so fast. It turns out that managing consistent state across each database instance spread around the world is a Seriously Hard Problem™.

There are a number of different approaches to solving this problem, each with trade-offs. One approach is to have a single primary region where all writes are sent to, and then asynchronously replicate those writes to the databases in other regions (often referred to as replicas). Writes can be potentially slower depending on how far away the primary region is from the user. Depending on the consistency model of the database (more on this below), reads can be looked at two ways:

Edge server and database architecture diagramAs you can see the diagram above, if your application can tolerate eventual reads for some or most data, you can potentially save a significant amount of latency by not going all the way back to the primary region for reads. The downside is that you may read data which has been updated on the primary region but not yet replicated to the region you are reading from. This is the approach that Deno KV takes with the nice bonus that KV lets you choose if you want to read from a primary or replica database.

 

Understanding database consistency

In an ideal world, an update to one database would instantly update all the replica databases around the world making them all consistent with each other. Unfortunately, the same latency issues that we are trying to solve with global databases work against us here, as updating all the global replicas takes time. The speed of light is only so fast.

There are a number of different consistency models that databases can support. Two common ones are:

The PACELC theorem nicely describes the trade-offs between consistency and latency. Stronger consistency means higher latency and the reverse is true as well with weaker consistency allowing for lower latency.

Let's imagine you are located in Australia and the primary region of the database in the US but with a replica in Australia. If someone from France updates a record on the database (which gets sent to the US) immediately before you read that record in Australia, depending on your consistency model, you may get the old value (eventual consistency) from the Australia replica or the new value (strong consistency) from the US primary region.

The consistency model that you use for your application will depend on your application's requirements and what the database is capable of. If you are building a banking application where it is critical to ensure a financial transaction correctly debits one account and credits another for the same amount, you will likely want to use strong consistency and  ACID transactions. However, if you are building a social media application, eventual consistency of your user's posts may be a better choice as having slightly stale posts is potentially a worthwhile trade-off for the significant performance boost of eventual reads.

For a much more in-depth discussion on database consistency in a globally distributed database, this 4 part series is an excellent read.

 

Global database options for Deploy

Running applications on Deno Deploy means serving requests from locations around the globe, from a location closest to the user. Ideally, the database would be located close to the server so that latency between the server and database is minimised for all the database calls made from the server. Therefore an ideal database for Deno Deploy would be one which was globally distributed in multiple regions to decrease latency and thus provide a better user experience. In this post/web application, we'll experiment with the following serverless databases which all offer multi-region replication and work with Deno Deploy:

Deno KV

Deno KV is a new global key-value database from the Deno team (currently in open beta). Reads are strongly consistent within the primary region and eventually consistent in replica regions. You can easily choose which consistency level you want for your reads. It is built on top of the open source FoundationDB (used by Apple's iCloud) and there is no configuration or setup. Data is replicated to at least 2 datacentres in each replica region. Deno KV currently has 4 replica regions (US East, US West, Europe and Asia) available. Access is via a custom but simple API layer. ACID transactions are supported globally and offer strict serializability, the strongest level of consistency possible.

DynamoDB

DynamoDB is a serverless NoSQL key-value database from AWS. For access, it supports a custom JSON API as well as PartiQL (a SQL-compatible query language). DynamoDB tables, by default, are deployed to a single region. To achieve a multi-region setup, you can enable global tables which creates identical tables in additional regions (in as many regions as you like). Only a single region in N. Virginia was configured for this experiment.

Strong consistency is offered within a single region only but not for secondary indexes. Global tables are eventually consistent with each other. DynamoDB also supports ACID transactions, but only within a single region. Transactions are not ACID compliant when replicating to other regions. DynamoDB also integrates extremely well with other AWS services as well as offering a host of enterprise features such as encryption at rest and a multitude of back and restore options.

Fauna

Fauna is a serverless NoSQL document-relational database offering two query languages, Fauna QL (FQL) and GraphQL. During database creation, you must choose between two region groups to host your database: US or Europe. Data is replicated to 3 geographic regions within the region group (i.e. US or Europe), but never outside that region group. For this experiment the US region group was chosen. True global replication is possible (e.g. hosting in US, Europe and Aisa) but only for enterprise customers through their Virtual Private Fauna offering.

Fauna offers strong consistency for all reads and writes as well as supporting ACID transactions. Both Deno KV and Fauna provide the strongest consistency model of the databases in the experiment. Despite being a NoSQL database, a strength of Fauna is its relational database capabilities such as normalisation, joins and indexes.

PlanetScale

PlanetScale offers a serverless MySQL-compatible database built on top of Vitess and is the only true relational database of the experiment. It offers 11 AWS regions with 4 GCP regions. For this experiment, a primary region of N. Virginia was selected. Additional replica regions are only available on paid plans (starting at $29/month) and are therefore not included in this experiment. Being a relational database, access to the data is done via normal SQL queries. A key offering is the ability to change the schema in isolated branches, similar to a git workflow. All data is automatically encrypted at rest. Like MySQL, it only offers eventual consistency.

Though serverless, PlanetScale isn't necessarily hands off as when your database becomes large you may need to intervene and apply sharding, which can be complicated.

Upstash Redis

Upstash takes the well known in-memory Redis database a step further with a durable Redis compatible global database. Access is via Redis APIs. It offers per request pricing and which scales to zero price if not used (storage still accrues cost). Upstash Redis only offers eventual consistency. For this experiment, a primary region of N. Virginia was configured with replicas setup in all available replica regions (California, Oregon, Frankfurt, Ireland, Singapore, Sydney and Sao Paulo). N.b. this would be a potentially expensive setup for a high volume application.

Summary

DatabaseTypeRegions configured in experiment
(* primary)
Read consistencyQuery modelTransactions
Deno KVKey/ValueUS East*, Europe, AsiaStrong (with optional eventual)Custom simple APIStrictly serializable ACID transactions
DynamoDBKey/ValueN. Virginia*Strong w/in single region (except for secondary indexes), eventual outwith (and optional within).PartiQL or custom CRUD APIAt best, serializable ACID transactions in single region only. Some operations are read-committed or not serializable
FaunaDocument storeUS*StrongCustom FaunaQL or GraphQLStrictly serializable ACID transactions
PlanetScaleRelationalN. Virginia*EventualSQLAvailable but not ACID compliant
Upstash RedisKey/ValueN. Virginia*, California, Oregon, Frankfurt, Ireland, Singapore, Sydney, Sao PauloEventualRedis APISerializable transactions (not ACID compliant)

 

Latency experiment

To be highly performant and give users the best experience, a globally distributed server needs a globally distributed database. How well does Deno's new KV database perform from regions around the globe and how does it compare to other globally distributed databases accessed from Deno Deploy?

Loading this page sent basic database write and read requests to each database. The database operations were executed from a Deno Deploy application running in the Google Cloud Platform (GCP) region/datacentre closest to you. Where the read or write operation was sent (i.e. which database region), and therefore the latency experienced, depends on how the database provider manages their network, where the primary database is, how many replicas are available, and what operation was used, amongst some factors influencing the latency.

All results represent the time for the database operation to execute, including the latency between the server (i.e. Deno Deploy application instance) and the database. The network latency between your browser and the server is not included in any result below.

The experiment aims to test the databases management and latency of global access. The queries are very simple and the data volumes are very small, both of which are unrealistic in a real-world application. By having simple queries and low volume data, the experiment allows the databases to perform at their fastest which in turn allows the experiment to focus on how the database provider manages the latency of global access.

The excellent WebPageTest was used to send requests to the different regions and provide the initial population of results.

Important: Please read the analysis on each database below to understand the results with the proper context. Generally speaking, the results are not always directly comparable as the databases have different setups, use cases, replica regions, configuration, etc. You should always do your own research, testing and benchmarking to determine which database is best for your use case.

 

Database latencies from your location

Upon loading this page, the following results were recorded for database requests from the Deno Deploy application (running in the region closest to you) to the various databases:

Your Deno Deploy region: N. Virginia

DBWriteTransactional writeEventual readStrong read
Deno KV15ms26ms15ms22ms
DynamoDB12ms24ms9ms8ms
FaunaErrorErrorErrorError
PlanetScaleErrorErrorErrorError
Upstash Redis98ms26ms6ms-
 

Database latencies from all over the world

Performance results from everyone who has loaded this page are summarised below, with stats updated daily.(Performance entries are held in Deno KV which returned and processed statistics for 0 performance measurements across 34 regions in 151ms.)

Show results for:

Deno KV

RegionWriteTransactional
write
Eventual
read
Strong
read
Belgium

111ms

min:93ms
max:413ms
p95:130ms

106ms

min:92ms
max:345ms
p95:131ms

29ms

min:12ms
max:102ms
p95:92ms

91ms

min:84ms
max:269ms
p95:97ms
Delhi

505ms

min:302ms
max:1196ms
p95:-

443ms

min:306ms
max:1138ms
p95:-

151ms

min:73ms
max:304ms
p95:-

305ms

min:298ms
max:318ms
p95:-
Finland

135ms

min:115ms
max:446ms
p95:158ms

127ms

min:114ms
max:450ms
p95:136ms

63ms

min:37ms
max:191ms
p95:121ms

116ms

min:108ms
max:226ms
p95:124ms
Frankfurt

115ms

min:99ms
max:425ms
p95:137ms

108ms

min:98ms
max:371ms
p95:116ms

44ms

min:5ms
max:172ms
p95:104ms

100ms

min:92ms
max:282ms
p95:110ms
Hong Kong

213ms

min:199ms
max:316ms
p95:229ms

213ms

min:199ms
max:449ms
p95:225ms

148ms

min:42ms
max:263ms
p95:217ms

202ms

min:193ms
max:218ms
p95:217ms
Iowa

50ms

min:35ms
max:129ms
p95:69ms

43ms

min:35ms
max:73ms
p95:53ms

33ms

min:28ms
max:100ms
p95:42ms

32ms

min:28ms
max:45ms
p95:38ms
Jakarta

349ms

min:255ms
max:919ms
p95:-

263ms

min:243ms
max:280ms
p95:-

80ms

min:20ms
max:258ms
p95:-

249ms

min:235ms
max:260ms
p95:-
Las Vegas

112ms

min:76ms
max:275ms
p95:262ms

127ms

min:73ms
max:264ms
p95:261ms

69ms

min:66ms
max:73ms
p95:71ms

68ms

min:66ms
max:71ms
p95:71ms
London

105ms

min:87ms
max:751ms
p95:125ms

99ms

min:88ms
max:552ms
p95:106ms

51ms

min:17ms
max:156ms
p95:96ms

88ms

min:81ms
max:166ms
p95:96ms
Los Angeles

130ms

min:77ms
max:20385ms
p95:116ms

88ms

min:77ms
max:801ms
p95:100ms

78ms

min:69ms
max:757ms
p95:99ms

78ms

min:70ms
max:210ms
p95:101ms
Madrid

113ms

min:92ms
max:141ms
p95:139ms

115ms

min:92ms
max:306ms
p95:130ms

37ms

min:30ms
max:89ms
p95:41ms

95ms

min:84ms
max:111ms
p95:107ms
Melbourne

238ms

min:223ms
max:278ms
p95:252ms

245ms

min:221ms
max:445ms
p95:256ms

103ms

min:91ms
max:227ms
p95:100ms

217ms

min:214ms
max:220ms
p95:220ms
Milan

120ms

min:108ms
max:148ms
p95:137ms

114ms

min:107ms
max:145ms
p95:123ms

28ms

min:15ms
max:112ms
p95:105ms

103ms

min:99ms
max:115ms
p95:112ms
Montreal

44ms

min:26ms
max:104ms
p95:66ms

39ms

min:24ms
max:1319ms
p95:46ms

23ms

min:18ms
max:55ms
p95:35ms

24ms

min:18ms
max:85ms
p95:35ms
Mumbai

341ms

min:280ms
max:1121ms
p95:346ms

322ms

min:281ms
max:1110ms
p95:337ms

147ms

min:67ms
max:316ms
p95:294ms

291ms

min:277ms
max:346ms
p95:304ms
N. Virginia

32ms

min:11ms
max:369ms
p95:77ms

27ms

min:10ms
max:245ms
p95:65ms

15ms

min:4ms
max:651ms
p95:48ms

16ms

min:5ms
max:215ms
p95:65ms
Netherlands

123ms

min:100ms
max:382ms
p95:144ms

115ms

min:99ms
max:374ms
p95:151ms

40ms

min:12ms
max:136ms
p95:103ms

98ms

min:91ms
max:148ms
p95:106ms
Ohio

43ms

min:24ms
max:110ms
p95:63ms

39ms

min:25ms
max:110ms
p95:52ms

27ms

min:18ms
max:134ms
p95:36ms

27ms

min:17ms
max:202ms
p95:35ms
Oregon

87ms

min:66ms
max:1868ms
p95:103ms

80ms

min:66ms
max:299ms
p95:100ms

69ms

min:60ms
max:322ms
p95:98ms

71ms

min:60ms
max:207ms
p95:101ms
Osaka

178ms

min:170ms
max:205ms
p95:185ms

179ms

min:171ms
max:187ms
p95:186ms

87ms

min:83ms
max:96ms
p95:90ms

165ms

min:162ms
max:171ms
p95:167ms
Salt Lake City

62ms

min:54ms
max:87ms
p95:81ms

61ms

min:56ms
max:73ms
p95:66ms

50ms

min:47ms
max:60ms
p95:56ms

52ms

min:47ms
max:66ms
p95:56ms
Santiago

190ms

min:152ms
max:211ms
p95:-

188ms

min:152ms
max:201ms
p95:-

170ms

min:118ms
max:180ms
p95:-

177ms

min:150ms
max:185ms
p95:-
Sao Paulo

158ms

min:126ms
max:501ms
p95:275ms

142ms

min:127ms
max:474ms
p95:147ms

129ms

min:120ms
max:266ms
p95:137ms

132ms

min:120ms
max:474ms
p95:146ms
Seoul

197ms

min:184ms
max:210ms
p95:209ms

203ms

min:183ms
max:330ms
p95:196ms

82ms

min:77ms
max:90ms
p95:88ms

182ms

min:177ms
max:191ms
p95:189ms
Singapore

254ms

min:224ms
max:310ms
p95:282ms

249ms

min:222ms
max:439ms
p95:273ms

28ms

min:5ms
max:250ms
p95:236ms

236ms

min:214ms
max:311ms
p95:257ms
South Carolina

208ms

min:23ms
max:30759ms
p95:85ms

37ms

min:24ms
max:204ms
p95:78ms

26ms

min:15ms
max:191ms
p95:67ms

33ms

min:15ms
max:996ms
p95:80ms
Sydney

220ms

min:204ms
max:261ms
p95:246ms

217ms

min:205ms
max:238ms
p95:232ms

113ms

min:99ms
max:338ms
p95:213ms

205ms

min:198ms
max:278ms
p95:209ms
Taiwan

216ms

min:189ms
max:720ms
p95:232ms

195ms

min:186ms
max:215ms
p95:209ms

112ms

min:51ms
max:204ms
p95:195ms

186ms

min:181ms
max:205ms
p95:201ms
Tel Aviv

161ms

min:140ms
max:527ms
p95:165ms

152ms

min:141ms
max:259ms
p95:158ms

61ms

min:60ms
max:65ms
p95:63ms

137ms

min:133ms
max:186ms
p95:137ms
Texas

67ms

min:43ms
max:431ms
p95:150ms

59ms

min:41ms
max:340ms
p95:123ms

43ms

min:34ms
max:217ms
p95:79ms

51ms

min:34ms
max:314ms
p95:111ms
Tokyo

1252ms

min:156ms
max:43271ms
p95:197ms

1389ms

min:156ms
max:38958ms
p95:193ms

108ms

min:76ms
max:232ms
p95:179ms

158ms

min:149ms
max:210ms
p95:177ms
Toronto

48ms

min:32ms
max:99ms
p95:64ms

44ms

min:32ms
max:106ms
p95:59ms

33ms

min:25ms
max:221ms
p95:37ms

31ms

min:26ms
max:72ms
p95:34ms
Warsaw

128ms

min:114ms
max:153ms
p95:149ms

123ms

min:115ms
max:133ms
p95:129ms

29ms

min:20ms
max:115ms
p95:111ms

111ms

min:108ms
max:163ms
p95:115ms
Zurich

173ms

min:105ms
max:10211ms
p95:141ms

115ms

min:106ms
max:197ms
p95:121ms

16ms

min:11ms
max:115ms
p95:18ms

103ms

min:99ms
max:167ms
p95:112ms

DynamoDB

RegionWriteTransactional
write
Eventual
read
Strong
read
Belgium

95ms

min:85ms
max:288ms
p95:116ms

103ms

min:96ms
max:181ms
p95:109ms

90ms

min:83ms
max:218ms
p95:106ms

88ms

min:83ms
max:167ms
p95:97ms
Delhi

276ms

min:262ms
max:288ms
p95:-

291ms

min:276ms
max:298ms
p95:-

275ms

min:261ms
max:284ms
p95:-

274ms

min:260ms
max:285ms
p95:-
Finland

117ms

min:107ms
max:316ms
p95:127ms

130ms

min:118ms
max:213ms
p95:146ms

114ms

min:106ms
max:180ms
p95:122ms

114ms

min:106ms
max:180ms
p95:123ms
Frankfurt

97ms

min:91ms
max:197ms
p95:104ms

110ms

min:101ms
max:226ms
p95:119ms

95ms

min:89ms
max:235ms
p95:103ms

94ms

min:89ms
max:211ms
p95:100ms
Hong Kong

222ms

min:199ms
max:558ms
p95:337ms

230ms

min:210ms
max:484ms
p95:282ms

207ms

min:198ms
max:414ms
p95:213ms

209ms

min:198ms
max:368ms
p95:223ms
Iowa

37ms

min:31ms
max:125ms
p95:40ms

50ms

min:40ms
max:82ms
p95:55ms

34ms

min:29ms
max:46ms
p95:37ms

34ms

min:30ms
max:52ms
p95:38ms
Jakarta

245ms

min:234ms
max:258ms
p95:-

258ms

min:248ms
max:274ms
p95:-

242ms

min:232ms
max:255ms
p95:-

241ms

min:233ms
max:254ms
p95:-
Las Vegas

69ms

min:67ms
max:73ms
p95:70ms

81ms

min:78ms
max:84ms
p95:83ms

69ms

min:64ms
max:92ms
p95:76ms

66ms

min:65ms
max:68ms
p95:67ms
London

86ms

min:80ms
max:282ms
p95:93ms

99ms

min:91ms
max:148ms
p95:109ms

83ms

min:79ms
max:146ms
p95:91ms

83ms

min:79ms
max:146ms
p95:89ms
Los Angeles

78ms

min:68ms
max:283ms
p95:100ms

89ms

min:79ms
max:621ms
p95:102ms

76ms

min:66ms
max:1166ms
p95:100ms

75ms

min:66ms
max:348ms
p95:100ms
Madrid

98ms

min:84ms
max:243ms
p95:106ms

108ms

min:94ms
max:133ms
p95:121ms

93ms

min:82ms
max:113ms
p95:105ms

94ms

min:82ms
max:130ms
p95:111ms
Melbourne

220ms

min:214ms
max:271ms
p95:219ms

229ms

min:225ms
max:244ms
p95:231ms

228ms

min:213ms
max:494ms
p95:216ms

215ms

min:212ms
max:223ms
p95:218ms
Milan

103ms

min:99ms
max:132ms
p95:106ms

115ms

min:109ms
max:128ms
p95:120ms

100ms

min:98ms
max:108ms
p95:104ms

100ms

min:98ms
max:112ms
p95:102ms
Montreal

23ms

min:18ms
max:87ms
p95:26ms

37ms

min:29ms
max:106ms
p95:50ms

20ms

min:16ms
max:56ms
p95:23ms

19ms

min:16ms
max:39ms
p95:23ms
Mumbai

254ms

min:205ms
max:660ms
p95:454ms

243ms

min:218ms
max:518ms
p95:253ms

226ms

min:202ms
max:451ms
p95:231ms

224ms

min:202ms
max:402ms
p95:235ms
N. Virginia

17ms

min:6ms
max:320ms
p95:62ms

31ms

min:15ms
max:321ms
p95:81ms

14ms

min:4ms
max:622ms
p95:56ms

11ms

min:4ms
max:97ms
p95:39ms
Netherlands

102ms

min:90ms
max:299ms
p95:117ms

109ms

min:99ms
max:187ms
p95:115ms

96ms

min:88ms
max:305ms
p95:102ms

95ms

min:87ms
max:478ms
p95:98ms
Ohio

31ms

min:23ms
max:246ms
p95:49ms

42ms

min:32ms
max:165ms
p95:58ms

26ms

min:21ms
max:95ms
p95:35ms

26ms

min:21ms
max:85ms
p95:33ms
Oregon

74ms

min:66ms
max:268ms
p95:97ms

89ms

min:75ms
max:1419ms
p95:107ms

71ms

min:64ms
max:128ms
p95:99ms

70ms

min:64ms
max:271ms
p95:95ms
Osaka

173ms

min:169ms
max:178ms
p95:177ms

187ms

min:181ms
max:192ms
p95:191ms

171ms

min:168ms
max:176ms
p95:172ms

170ms

min:167ms
max:173ms
p95:172ms
Salt Lake City

59ms

min:53ms
max:102ms
p95:67ms

69ms

min:63ms
max:91ms
p95:72ms

54ms

min:52ms
max:74ms
p95:58ms

53ms

min:51ms
max:59ms
p95:55ms
Santiago

171ms

min:121ms
max:181ms
p95:-

185ms

min:137ms
max:199ms
p95:-

168ms

min:118ms
max:177ms
p95:-

167ms

min:118ms
max:176ms
p95:-
Sao Paulo

128ms

min:120ms
max:242ms
p95:156ms

143ms

min:132ms
max:254ms
p95:176ms

127ms

min:119ms
max:240ms
p95:158ms

122ms

min:118ms
max:155ms
p95:130ms
Seoul

190ms

min:186ms
max:198ms
p95:194ms

204ms

min:201ms
max:216ms
p95:204ms

187ms

min:185ms
max:200ms
p95:187ms

189ms

min:185ms
max:215ms
p95:187ms
Singapore

242ms

min:221ms
max:523ms
p95:248ms

256ms

min:234ms
max:459ms
p95:285ms

231ms

min:221ms
max:295ms
p95:247ms

236ms

min:221ms
max:447ms
p95:251ms
South Carolina

41ms

min:23ms
max:688ms
p95:96ms

51ms

min:34ms
max:212ms
p95:103ms

33ms

min:21ms
max:304ms
p95:86ms

29ms

min:21ms
max:99ms
p95:60ms
Sydney

213ms

min:202ms
max:414ms
p95:214ms

219ms

min:212ms
max:243ms
p95:227ms

207ms

min:200ms
max:372ms
p95:211ms

206ms

min:201ms
max:399ms
p95:206ms
Taiwan

203ms

min:189ms
max:597ms
p95:199ms

206ms

min:199ms
max:240ms
p95:214ms

190ms

min:186ms
max:213ms
p95:197ms

194ms

min:186ms
max:370ms
p95:197ms
Tel Aviv

134ms

min:131ms
max:141ms
p95:136ms

148ms

min:144ms
max:158ms
p95:151ms

133ms

min:130ms
max:159ms
p95:135ms

132ms

min:130ms
max:137ms
p95:134ms
Texas

43ms

min:36ms
max:147ms
p95:56ms

55ms

min:47ms
max:155ms
p95:75ms

40ms

min:35ms
max:113ms
p95:53ms

40ms

min:35ms
max:261ms
p95:48ms
Tokyo

170ms

min:157ms
max:371ms
p95:176ms

179ms

min:169ms
max:331ms
p95:187ms

164ms

min:155ms
max:313ms
p95:172ms

161ms

min:154ms
max:177ms
p95:172ms
Toronto

31ms

min:25ms
max:101ms
p95:32ms

43ms

min:36ms
max:76ms
p95:54ms

27ms

min:23ms
max:41ms
p95:29ms

27ms

min:24ms
max:37ms
p95:29ms
Warsaw

109ms

min:105ms
max:133ms
p95:113ms

121ms

min:116ms
max:148ms
p95:124ms

107ms

min:104ms
max:141ms
p95:109ms

106ms

min:104ms
max:120ms
p95:107ms
Zurich

101ms

min:96ms
max:145ms
p95:113ms

112ms

min:106ms
max:176ms
p95:118ms

98ms

min:95ms
max:120ms
p95:106ms

98ms

min:95ms
max:154ms
p95:101ms

Fauna

RegionWriteTransactional
write
Eventual
read
Strong
read
Belgium

379ms

min:122ms
max:1678ms
p95:551ms

164ms

min:120ms
max:431ms
p95:196ms

-

129ms

min:103ms
max:372ms
p95:233ms
Delhi

736ms

min:295ms
max:957ms
p95:-

269ms

min:233ms
max:357ms
p95:-

-

237ms

min:221ms
max:278ms
p95:-
Finland

499ms

min:152ms
max:1012ms
p95:743ms

199ms

min:150ms
max:473ms
p95:255ms

-

159ms

min:128ms
max:475ms
p95:229ms
Frankfurt

318ms

min:122ms
max:893ms
p95:501ms

174ms

min:122ms
max:847ms
p95:230ms

-

123ms

min:106ms
max:283ms
p95:163ms
Hong Kong

411ms

min:218ms
max:1321ms
p95:771ms

252ms

min:220ms
max:711ms
p95:324ms

-

180ms

min:164ms
max:370ms
p95:254ms
Iowa

262ms

min:72ms
max:596ms
p95:365ms

118ms

min:69ms
max:349ms
p95:142ms

-

64ms

min:49ms
max:427ms
p95:118ms
Jakarta

1042ms

min:650ms
max:1354ms
p95:-

307ms

min:250ms
max:441ms
p95:-

-

261ms

min:196ms
max:389ms
p95:-
Las Vegas

231ms

min:128ms
max:318ms
p95:252ms

118ms

min:106ms
max:137ms
p95:129ms

-

72ms

min:51ms
max:147ms
p95:139ms
London

361ms

min:110ms
max:859ms
p95:538ms

148ms

min:107ms
max:529ms
p95:190ms

-

116ms

min:92ms
max:366ms
p95:171ms
Los Angeles

218ms

min:94ms
max:879ms
p95:348ms

117ms

min:96ms
max:1164ms
p95:148ms

-

57ms

min:41ms
max:518ms
p95:100ms
Madrid

485ms

min:161ms
max:1146ms
p95:633ms

191ms

min:137ms
max:454ms
p95:208ms

-

137ms

min:115ms
max:351ms
p95:202ms
Melbourne

583ms

min:226ms
max:892ms
p95:764ms

238ms

min:227ms
max:292ms
p95:244ms

-

179ms

min:171ms
max:274ms
p95:179ms
Milan

435ms

min:145ms
max:875ms
p95:604ms

189ms

min:140ms
max:276ms
p95:206ms

-

128ms

min:117ms
max:203ms
p95:185ms
Montreal

212ms

min:47ms
max:490ms
p95:301ms

107ms

min:46ms
max:578ms
p95:134ms

-

40ms

min:29ms
max:377ms
p95:70ms
Mumbai

608ms

min:224ms
max:1179ms
p95:943ms

275ms

min:222ms
max:543ms
p95:303ms

-

229ms

min:204ms
max:583ms
p95:279ms
N. Virginia

182ms

min:36ms
max:676ms
p95:330ms

87ms

min:34ms
max:1587ms
p95:121ms

-

39ms

min:18ms
max:314ms
p95:100ms
Netherlands

384ms

min:167ms
max:645ms
p95:495ms

176ms

min:116ms
max:436ms
p95:228ms

-

117ms

min:100ms
max:298ms
p95:146ms
Ohio

270ms

min:101ms
max:608ms
p95:396ms

112ms

min:54ms
max:534ms
p95:132ms

-

45ms

min:35ms
max:203ms
p95:87ms
Oregon

759ms

min:83ms
max:132782ms
p95:527ms

108ms

min:84ms
max:1458ms
p95:137ms

-

49ms

min:30ms
max:256ms
p95:98ms
Osaka

487ms

min:179ms
max:955ms
p95:848ms

184ms

min:177ms
max:193ms
p95:192ms

-

125ms

min:118ms
max:147ms
p95:138ms
Salt Lake City

194ms

min:113ms
max:331ms
p95:310ms

124ms

min:112ms
max:249ms
p95:130ms

-

60ms

min:56ms
max:76ms
p95:62ms
Santiago

726ms

min:246ms
max:933ms
p95:-

258ms

min:247ms
max:286ms
p95:-

-

198ms

min:180ms
max:273ms
p95:-
Sao Paulo

581ms

min:152ms
max:1656ms
p95:1242ms

194ms

min:146ms
max:413ms
p95:267ms

-

155ms

min:131ms
max:356ms
p95:189ms
Seoul

537ms

min:198ms
max:828ms
p95:763ms

204ms

min:190ms
max:225ms
p95:213ms

-

143ms

min:133ms
max:163ms
p95:147ms
Singapore

733ms

min:251ms
max:1640ms
p95:1275ms

264ms

min:235ms
max:479ms
p95:300ms

-

199ms

min:180ms
max:394ms
p95:211ms
South Carolina

234ms

min:55ms
max:1096ms
p95:366ms

106ms

min:47ms
max:705ms
p95:131ms

-

47ms

min:29ms
max:403ms
p95:102ms
Sydney

478ms

min:214ms
max:1175ms
p95:723ms

228ms

min:215ms
max:458ms
p95:237ms

-

170ms

min:159ms
max:380ms
p95:200ms
Taiwan

685ms

min:209ms
max:1994ms
p95:943ms

228ms

min:206ms
max:436ms
p95:258ms

-

172ms

min:150ms
max:378ms
p95:200ms
Tel Aviv

712ms

min:308ms
max:1130ms
p95:1074ms

346ms

min:303ms
max:380ms
p95:366ms

-

293ms

min:286ms
max:330ms
p95:308ms
Texas

246ms

min:65ms
max:841ms
p95:387ms

125ms

min:61ms
max:481ms
p95:164ms

-

62ms

min:48ms
max:280ms
p95:102ms
Tokyo

473ms

min:185ms
max:1500ms
p95:793ms

197ms

min:181ms
max:394ms
p95:207ms

-

141ms

min:123ms
max:498ms
p95:176ms
Toronto

244ms

min:106ms
max:486ms
p95:335ms

102ms

min:56ms
max:122ms
p95:116ms

-

56ms

min:38ms
max:264ms
p95:98ms
Warsaw

459ms

min:166ms
max:996ms
p95:558ms

194ms

min:148ms
max:268ms
p95:202ms

-

129ms

min:122ms
max:174ms
p95:151ms
Zurich

394ms

min:124ms
max:739ms
p95:477ms

183ms

min:129ms
max:371ms
p95:208ms

-

115ms

min:108ms
max:239ms
p95:141ms

PlanetScale

RegionWriteTransactional
write
Eventual
read
Strong
read
Belgium

165ms

min:94ms
max:307ms
p95:213ms

561ms

min:411ms
max:629ms
p95:614ms

125ms

min:94ms
max:232ms
p95:163ms

-

Delhi

397ms

min:229ms
max:536ms
p95:-

1019ms

min:937ms
max:1082ms
p95:-

244ms

min:233ms
max:275ms
p95:-

-

Finland

271ms

min:130ms
max:481ms
p95:382ms

712ms

min:596ms
max:913ms
p95:756ms

167ms

min:154ms
max:277ms
p95:201ms

-

Frankfurt

126ms

min:101ms
max:360ms
p95:184ms

494ms

min:392ms
max:799ms
p95:571ms

118ms

min:97ms
max:277ms
p95:148ms

-

Hong Kong

333ms

min:258ms
max:514ms
p95:458ms

1279ms

min:1140ms
max:1508ms
p95:1399ms

322ms

min:282ms
max:375ms
p95:350ms

-

Iowa

147ms

min:47ms
max:222ms
p95:195ms

386ms

min:227ms
max:438ms
p95:406ms

95ms

min:47ms
max:122ms
p95:115ms

-

Jakarta

509ms

min:339ms
max:947ms
p95:-

1175ms

min:1078ms
max:1233ms
p95:-

273ms

min:244ms
max:286ms
p95:-

-

Las Vegas

260ms

min:118ms
max:315ms
p95:304ms

661ms

min:589ms
max:737ms
p95:724ms

196ms

min:145ms
max:208ms
p95:205ms

-

London

123ms

min:88ms
max:419ms
p95:158ms

435ms

min:336ms
max:832ms
p95:503ms

95ms

min:83ms
max:158ms
p95:131ms

-

Los Angeles

204ms

min:102ms
max:1670ms
p95:291ms

606ms

min:395ms
max:3794ms
p95:682ms

161ms

min:97ms
max:1191ms
p95:190ms

-

Madrid

228ms

min:112ms
max:427ms
p95:337ms

656ms

min:547ms
max:910ms
p95:702ms

144ms

min:117ms
max:186ms
p95:181ms

-

Melbourne

383ms

min:220ms
max:1376ms
p95:492ms

1035ms

min:922ms
max:1062ms
p95:1048ms

243ms

min:228ms
max:325ms
p95:272ms

-

Milan

199ms

min:110ms
max:542ms
p95:290ms

593ms

min:464ms
max:670ms
p95:648ms

130ms

min:116ms
max:194ms
p95:175ms

-

Montreal

109ms

min:25ms
max:339ms
p95:181ms

272ms

min:116ms
max:395ms
p95:369ms

71ms

min:24ms
max:115ms
p95:89ms

-

Mumbai

271ms

min:197ms
max:608ms
p95:487ms

893ms

min:778ms
max:1306ms
p95:939ms

211ms

min:193ms
max:586ms
p95:242ms

-

N. Virginia

53ms

min:11ms
max:335ms
p95:122ms

177ms

min:22ms
max:845ms
p95:299ms

56ms

min:6ms
max:314ms
p95:99ms

-

Netherlands

172ms

min:109ms
max:329ms
p95:241ms

560ms

min:382ms
max:1008ms
p95:636ms

122ms

min:95ms
max:375ms
p95:157ms

-

Ohio

135ms

min:29ms
max:339ms
p95:222ms

329ms

min:222ms
max:591ms
p95:413ms

87ms

min:54ms
max:241ms
p95:116ms

-

Oregon

419ms

min:82ms
max:130666ms
p95:330ms

475ms

min:383ms
max:722ms
p95:534ms

110ms

min:87ms
max:1515ms
p95:143ms

-

Osaka

252ms

min:179ms
max:396ms
p95:341ms

877ms

min:803ms
max:1060ms
p95:893ms

194ms

min:168ms
max:237ms
p95:232ms

-

Salt Lake City

176ms

min:110ms
max:285ms
p95:271ms

684ms

min:594ms
max:749ms
p95:710ms

190ms

min:152ms
max:214ms
p95:205ms

-

Santiago

451ms

min:185ms
max:651ms
p95:-

962ms

min:887ms
max:999ms
p95:-

228ms

min:218ms
max:237ms
p95:-

-

Sao Paulo

177ms

min:125ms
max:1166ms
p95:297ms

577ms

min:489ms
max:721ms
p95:670ms

136ms

min:121ms
max:193ms
p95:171ms

-

Seoul

411ms

min:206ms
max:650ms
p95:623ms

1035ms

min:985ms
max:1077ms
p95:1061ms

247ms

min:217ms
max:285ms
p95:284ms

-

Singapore

285ms

min:222ms
max:629ms
p95:362ms

1099ms

min:956ms
max:1563ms
p95:1153ms

259ms

min:221ms
max:651ms
p95:289ms

-

South Carolina

145ms

min:27ms
max:931ms
p95:292ms

337ms

min:279ms
max:606ms
p95:448ms

96ms

min:45ms
max:732ms
p95:120ms

-

Sydney

265ms

min:207ms
max:630ms
p95:411ms

964ms

min:827ms
max:1358ms
p95:988ms

224ms

min:204ms
max:262ms
p95:253ms

-

Taiwan

361ms

min:212ms
max:553ms
p95:513ms

1013ms

min:910ms
max:1220ms
p95:1097ms

250ms

min:220ms
max:553ms
p95:253ms

-

Tel Aviv

434ms

min:150ms
max:747ms
p95:694ms

1238ms

min:894ms
max:1360ms
p95:1353ms

301ms

min:204ms
max:380ms
p95:376ms

-

Texas

172ms

min:43ms
max:389ms
p95:279ms

424ms

min:198ms
max:670ms
p95:466ms

108ms

min:48ms
max:167ms
p95:129ms

-

Tokyo

217ms

min:158ms
max:552ms
p95:307ms

786ms

min:678ms
max:1046ms
p95:856ms

188ms

min:155ms
max:528ms
p95:223ms

-

Toronto

155ms

min:46ms
max:301ms
p95:223ms

384ms

min:368ms
max:430ms
p95:403ms

96ms

min:84ms
max:115ms
p95:112ms

-

Warsaw

219ms

min:116ms
max:582ms
p95:333ms

628ms

min:508ms
max:679ms
p95:655ms

137ms

min:126ms
max:185ms
p95:181ms

-

Zurich

179ms

min:108ms
max:472ms
p95:270ms

573ms

min:441ms
max:634ms
p95:600ms

118ms

min:109ms
max:172ms
p95:154ms

-

Upstash Redis

RegionWriteTransactional
write
Eventual
read
Strong
read
Belgium

211ms

min:109ms
max:385ms
p95:278ms

400ms

min:387ms
max:571ms
p95:402ms

14ms

min:12ms
max:71ms
p95:18ms

-

Delhi

661ms

min:320ms
max:832ms
p95:-

1005ms

min:938ms
max:1042ms
p95:-

77ms

min:68ms
max:86ms
p95:-

-

Finland

340ms

min:128ms
max:629ms
p95:552ms

419ms

min:401ms
max:691ms
p95:424ms

35ms

min:30ms
max:275ms
p95:40ms

-

Frankfurt

169ms

min:98ms
max:556ms
p95:315ms

391ms

min:376ms
max:705ms
p95:401ms

5ms

min:2ms
max:49ms
p95:9ms

-

Hong Kong

366ms

min:256ms
max:572ms
p95:509ms

1016ms

min:896ms
max:1236ms
p95:1174ms

39ms

min:37ms
max:65ms
p95:42ms

-

Iowa

207ms

min:31ms
max:392ms
p95:309ms

43ms

min:28ms
max:56ms
p95:54ms

31ms

min:28ms
max:59ms
p95:34ms

-

Jakarta

454ms

min:389ms
max:567ms
p95:-

970ms

min:891ms
max:998ms
p95:-

19ms

min:16ms
max:28ms
p95:-

-

Las Vegas

221ms

min:190ms
max:271ms
p95:268ms

286ms

min:278ms
max:331ms
p95:287ms

19ms

min:17ms
max:21ms
p95:20ms

-

London

195ms

min:85ms
max:1965ms
p95:279ms

307ms

min:295ms
max:364ms
p95:312ms

14ms

min:11ms
max:60ms
p95:16ms

-

Los Angeles

171ms

min:73ms
max:1163ms
p95:262ms

281ms

min:263ms
max:1201ms
p95:325ms

12ms

min:9ms
max:111ms
p95:15ms

-

Madrid

281ms

min:126ms
max:523ms
p95:379ms

413ms

min:404ms
max:421ms
p95:419ms

30ms

min:26ms
max:40ms
p95:35ms

-

Melbourne

378ms

min:217ms
max:565ms
p95:483ms

822ms

min:818ms
max:838ms
p95:824ms

15ms

min:14ms
max:16ms
p95:15ms

-

Milan

238ms

min:108ms
max:492ms
p95:442ms

397ms

min:392ms
max:407ms
p95:402ms

13ms

min:11ms
max:21ms
p95:14ms

-

Montreal

141ms

min:15ms
max:389ms
p95:215ms

27ms

min:15ms
max:97ms
p95:39ms

17ms

min:15ms
max:133ms
p95:19ms

-

Mumbai

619ms

min:274ms
max:1228ms
p95:844ms

1012ms

min:538ms
max:1230ms
p95:1062ms

67ms

min:61ms
max:226ms
p95:72ms

-

N. Virginia

88ms

min:3ms
max:613ms
p95:195ms

22ms

min:2ms
max:631ms
p95:64ms

8ms

min:3ms
max:297ms
p95:19ms

-

Netherlands

221ms

min:108ms
max:425ms
p95:287ms

398ms

min:389ms
max:605ms
p95:400ms

13ms

min:10ms
max:111ms
p95:18ms

-

Ohio

165ms

min:19ms
max:372ms
p95:268ms

33ms

min:19ms
max:85ms
p95:44ms

23ms

min:18ms
max:249ms
p95:25ms

-

Oregon

449ms

min:64ms
max:131056ms
p95:349ms

282ms

min:64ms
max:1574ms
p95:299ms

19ms

min:12ms
max:144ms
p95:49ms

-

Osaka

595ms

min:324ms
max:934ms
p95:748ms

1021ms

min:938ms
max:1069ms
p95:1065ms

83ms

min:82ms
max:84ms
p95:84ms

-

Salt Lake City

209ms

min:109ms
max:346ms
p95:317ms

316ms

min:300ms
max:329ms
p95:326ms

43ms

min:39ms
max:46ms
p95:46ms

-

Santiago

541ms

min:173ms
max:748ms
p95:-

522ms

min:518ms
max:529ms
p95:-

54ms

min:51ms
max:59ms
p95:-

-

Sao Paulo

221ms

min:120ms
max:494ms
p95:424ms

477ms

min:468ms
max:496ms
p95:485ms

4ms

min:2ms
max:21ms
p95:8ms

-

Seoul

588ms

min:312ms
max:732ms
p95:683ms

1025ms

min:945ms
max:1059ms
p95:1051ms

79ms

min:70ms
max:99ms
p95:85ms

-

Singapore

364ms

min:217ms
max:502ms
p95:479ms

956ms

min:843ms
max:1283ms
p95:1000ms

4ms

min:2ms
max:15ms
p95:6ms

-

South Carolina

179ms

min:19ms
max:929ms
p95:307ms

45ms

min:20ms
max:903ms
p95:85ms

29ms

min:20ms
max:498ms
p95:67ms

-

Sydney

283ms

min:204ms
max:576ms
p95:399ms

811ms

min:805ms
max:838ms
p95:816ms

3ms

min:2ms
max:6ms
p95:5ms

-

Taiwan

549ms

min:286ms
max:702ms
p95:613ms

1013ms

min:906ms
max:1565ms
p95:1042ms

50ms

min:43ms
max:65ms
p95:60ms

-

Tel Aviv

411ms

min:153ms
max:803ms
p95:725ms

473ms

min:433ms
max:507ms
p95:505ms

89ms

min:56ms
max:123ms
p95:122ms

-

Texas

302ms

min:109ms
max:621ms
p95:444ms

315ms

min:294ms
max:644ms
p95:361ms

50ms

min:42ms
max:986ms
p95:52ms

-

Tokyo

569ms

min:291ms
max:850ms
p95:684ms

1036ms

min:926ms
max:1710ms
p95:1091ms

77ms

min:71ms
max:87ms
p95:83ms

-

Toronto

176ms

min:22ms
max:395ms
p95:302ms

36ms

min:22ms
max:101ms
p95:46ms

26ms

min:21ms
max:82ms
p95:34ms

-

Warsaw

275ms

min:114ms
max:509ms
p95:411ms

401ms

min:398ms
max:410ms
p95:404ms

19ms

min:17ms
max:38ms
p95:21ms

-

Zurich

207ms

min:106ms
max:544ms
p95:310ms

393ms

min:378ms
max:500ms
p95:397ms

9ms

min:8ms
max:16ms
p95:11ms

-

 

Analysis

Deno KV

MetricRating
Setup/Configuration★★★★★
Local development★★★★☆
Global distribution★★★★☆
Ease of use★★★★☆
Performance★★★★★
Consistency★★★★★
Features/Flexibility★★★☆☆
Vendor independence★★☆☆☆

Setup/Configuration: Deno KV easily tops the bunch when it comes to setup and configuration, simply because there is none. You do not have to create a database, manage connection strings, create credentials, choose regions, manage usernames and passwords, or anything else. You just start coding. Getting started with KV was significantly faster and easier than any of the other solutions. The Deno core team have suggested in the future some configuration may be available around regions (choice of primary region and limiting data to specific regions for example).

Local development: Local development is also very easy, again there is no setup. In production, you are using a globally distributed database built on FoundationDB, and locally you are using a SQLite database which ships with the Deno CLI. The difference is transparent as the API doesn't change. There's nothing you need to do between development and production setup. As a beta product with few features, manual effort is needed to populate data into KV stores on another dev machine or Deploy branch build. Manual work to manage and delete these branch build KV stores may also be required if they contribute to storage costs. Using an access token you can access your remote KV store locally, which is very handy for testing and local development.

Global distribution: With database replicas on 3 continents, KV counts as being a truly global database. Deploy Free tier customers are limited to a single read/write region. Deploy Pro users can configure which read regions are enabled (up to 4), while enterprise customers can further configure which region is the primary replica. The Deno team have hinted they are looking at adding additional replicas and capabilities to manage regions.

Ease of use: Ease of use also scored very high. The API is simple and intuitive and the nascent documentation is decent. Where Deno KV is less user friendly is the manual management required for secondary indexes. You must manually create and carefully manage these. It's not overly difficult, but neither is it handled automatically for you. Expect to see libraries which help manage this. KV's approach to keys, built from various parts, allows for nice flexibility of modelling your data, within the confines of a key-value database, as well as good ability to do range searches.

Performance: KV is impressively fast. Strongly consistent read, write performance and transactions are all either the fastest or very close to the fastest measured in any region of the databases tested. Eventual read performance is also very fast, second only to Upstash Redis which has many more global replicas configured.

Consistency: KV is strongly consistent, up there with Fauna as the most consistent database tested. However, unlike Fauna, KV has the nice option of allowing eventual reads for faster access in use cases where strong consistency is not required.

Features/Flexibility: Features and flexibility are one of KV's weaker points. Like all key-value stores, KV is not best suited to highly relational data. There are no backup capabilities, data streaming, security configuration, or other advanced features, though the core team have confirmed that KV's data is always encrypted at rest. Additionally, of the key-value stores out there, KV has fairly restrictive limits on key length (2kb) and value length (64kb), making it unsuitable for some types of data. There is also a limit of 1000 operations per transaction (or 800kb transaction size, whichever is hit first). KV recently introduced the ability to remotely connect to a KV store on Deploy, allowing containerised apps to connect to KV for example. It's also useful for import and export of data to KV. Finally, as a beta product, KV lacks maturity in dashboard tooling. Expect to see improvements in all these areas as KV matures.

Vendor independence: KV's weakest point is perhaps it's vendor lock-in. As a globally distributed database, KV is only available in Deno Deploy. However, with the new addition of remote connections to KV, it's possible access KV from other edge platforms via containerised Deno deployments. Access from other runtimes is not supported. Deno also has a custom API meaning you cannot simply swap out KV for another database if in the future you migrate off of Deploy or away from KV. That said, the API is very simple so migrations may not be overly difficult. The core team have also hinted at potentially allowing KV to be used outside of Deploy in the future.

Pricing: Pricing has now been announced for Deno KV. Free tier is capped at 1GB of storage, while the $20/month Pro tier comes with 5GB included. In an unusual move, KV places usage caps per day rather than per month. Also of note, the Pro tier isn't just for the database, but for Deploy hosting as well. E.g. for the Pro plan, if you stay within the 5GB limit and 45K/read, 15k/write per day, you effectively get KV for free if you are paying to host anyway. Exceeding the KV plan limits appears to be much more expensive than most of the competing databases (except perhaps Upstash Redis), though this significantly depends on your workload and comparisons are hard.

DynamoDB

MetricRating
Setup/Configuration★★★★☆
Local development★★★★☆
Global distribution★★★☆☆
Ease of use★★★☆☆
Performance★★★★☆
Consistency★★★☆☆
Features/Flexibility★★★★★
Vendor independence★★★☆☆

Setup/Configuration: As you'd expect from AWS, DynamoDB is highly configurable and can be created in a number of ways including programmatically. The console is easy to use and well integrated into the other services AWS offers. Creating a DynamoDB table requires setting the partition key (i.e. primary index), so a basic understanding of how DynamoDB works is necessary to start.

Local development: AWS provide an executable jar, maven dependency (both Java) or Docker image for local development. Data files can be specified for pre-population and sharing.

Global distribution: This was a complicated one to rate. On the one hand, DynamoDB offers "global tables" which are replicated tables, offered across 16 different regions. Picking and choosing which regions you want including which is your primary region is great flexibility. However, there are a number of caveats. For example, using global tables introduces a weaker consistency model. Another challenge is that when using global tables, routing of the request is complicated. Unlike other providers where requests are automatically routed to the closest replica region, in DynamoDB using global tables, you must either implement the routing logic in the client yourself (e.g. manually map Deploy region to AWS Global Table region) or place a compute layer in front of DynamoDB in each replica region. Then, in front of the compute layer is another service like Route53 which can route the request to the closest compute layer. Considerations like region outages must either be explicity coded for in the client or health checks configured in Route53 to route around the outage.

Ease of use: Ease of use was average amongst the databases tested. The console is easy to use and well integrated into the other services AWS offers. Understanding how DynamoDB partition keys work is important to utilising the service effectively. Documentation was generally good, however a reasonable amount of reading was required to understand how to use the API. It felt very counter-intuitive to specify the region in the client. The API is also very verbose, requiring a lot of code to achieve simple tasks. There are few examples of using DynamoDB with Deno and even the Deno Deploy example is broken and incomplete.

Performance: Another challenging one to rate. This experiment only used a single region deployment of DynamoDB, so it was never going to be competitive in reads with other databases having multiple replica regions. And yet, it still performed well, achieving best or second best write performance in every region. The biggest let down in performance comes from the first use of the API which incurs a ~200-600ms delay, effectively a cold start penalty and something not encountered in any of the other databases. To make the experiment more consistent and comparable, a dummy request is sent to the API before the experimental requests are sent to eliminate this cold start penalty. However real world apps will take this hit on every new isolate creation in Deno Deploy so should be carefully considered.

Consistency: DynamoDB's consistency model is somewhat complicated. If using a single region only you get strong consistency writes and optionally reads too (default is eventual consistency reads). However, if using global tables, and you specified a "strong consistent read" it will only be strongly consistent for writes within the same region. This means global tables are effectively only eventually consistent. Cross region transactions are not ACID compliant leading to potential data loss if concurrent writes to the same data occur in multiple regions.

Features/Flexibility: Again, as you would expect from AWS, DynamoDB has many features and is very flexible. It is especially good at integrating into other AWS services. Data can be imported/exported to S3. Other features include data trigger functions, encryption at rest, point in time recovery, on-demand backup and restore, and much more.

Vendor independence: Like Deno KV, DynamoDB is not vendor independent. Once you start using it, migrating away will be difficult. However, while migrating to a different database is difficult, migrating to a different edge server (e.g. Cloudflare) is easy as DynamoDB will work with any provider through it's http interface.

Pricing: DynamoDB costs can be a challenge to compute. In the general, reads and writes are reasonably priced, storage is among the cheapest, with the first 25GB of storage free. Alongside Upstash, it provides a serverless pricing model (pay for only what you use). However, the cost of global tables can quickly add up as each region added incurs additional linear costs for writes and storage.

Fauna

MetricRating
Setup/Configuration★★★☆☆
Local development★★★★☆
Global distribution★★☆☆☆
Ease of use★★☆☆☆
Performance★★★★☆
Consistency★★★★★
Features/Flexibility★★★★★
Vendor independence★★★☆☆

Setup/Configuration: Creating a Fauna database is straightforward via their web UI. Once the database is created you need to create a Collection, similar to a table in a traditional database, via the UI, in their database specific Fauna Query Language (FQL) or via their GraphQL API. You can also add a GraphQL schema to your Collection. Finally, you need to create a security key to access your database via the javascript client or http POST request. While nothing was overly difficult, the process was not as simple as other databases and there is a lot of new terminology to learn.

Local development: For local development, Fauna offers a docker container to run a local instance of Fauna which must be installed and given minor configuration to run. You can run it with persisted data or start with a clean sheet.

Global distribution: Fauna bills itself as a multi-region distributed database. However, without upgrading to their enterprise plan (which gets you VM isolated single tenant customised deployments anywhere you want), you are limited to either Western centric US or Europe region groups (but not a mixture). With the region group, there will be 3 replicas of your data within the region. Speaking with their support, potential changes are coming to offer an expanded global offering. As of now, however, this may not be ideal if your primary user base is in Asia for example.

Ease of use: Fauna had the steepest learning curve of the databases reviewed, however, if you already know GraphQL this will help. Fauna's FQL is a powerful language but as a custom built API takes time to learn. The documentation on the website is OK but lacking at times. It will take considerable time to become comfortable with Fauna as conceptually it is very different to other databases. There are few examples of using Fauna with Deno and even the guide on Deno Deploy documentation can be a challenge to follow.

Performance: Performance wise, Fauna held its ground well, despite being limited to a single region group. Writes were slow compared to the other databases, but strong reads were fast, though as Fauna does not offer eventual consistency reads other databases can significantly outperform Fauna if eventual consistency is acceptable.

Consistency: Fauna, like KV, offers very strong consistency but as mentioned previously there is no option for eventual read consistency. This is likely due to the fact that Fauna is an active-active database where writes only complete after replication to all replicas. Everything in Fauna is a transaction.

Features/Flexibility: Where Fauna really shines is in it's features and flexibility. If you invest the time to properly learn Fauna, it will reward you with capabilities not found in other NoSQL databases such as joins, indexes, normalised data, SQL like queries, functions (which are similar to stored procedures), data streaming, backups, temporality (reading data as it was at a point in time), and more.

Vendor independence: Fauna is a proprietary database with a custom API and many features. Once your application is deeply embedded into Fauna migrating to another database will be difficult and costly. On the plus side, unlike KV you can take your Fauna database with you to another edge platform and as the GraphQL API is pure http based there are no libraries to worry about. Alternatively, using Airbyte you can extract your data from Fauna and move it elsewhere.

Pricing: There are 7 metrics Fauna uses in its pricing model. Their entry level plan gets you $25 worth of services each month which equates to a maximum of 54 million reads, 11 million writes or 25GB of storage. Costs appear to be middle of the road.

PlanetScale

MetricRating
Setup/Configuration★★★★☆
Local development★★☆☆☆
Global distribution★★★★☆
Ease of use★★★☆☆
Performance★★★☆☆
Consistency★★☆☆☆
Features/Flexibility★★★★☆
Vendor independence★★★★☆

Setup/Configuration: Setup of a PlanetScale database is straightforward via their UI. In addition to a name, you also select a primary region. Free plans are limited to a single region and single database. Like any SQL database, you need to define a schema using traditional SQL (e.g. "CREATE TABLE ...").

Local development: PlanetScale does not provide a local development option. Your choices are to connect to a development branch of your database which requires a network connection and incurs usage charges, or manually setup and connect to a local MySQL instance. No instructions are given for the latter.

Global distribution: In addition to selecting your primary region from 11 AWS or 4 GCP (beta) regions, you can also enable one or more read-only replica regions. One downside to PlanetScale's global setup is that, similar to DynamoDB, you must manage the connections yourself in the client (e.g. decide which region to connect to), unlike other providers who route you to the closest region automatically.

Ease of use: PlanetScale is essentially a MySQL database under the hood and therefore you have all the power and flexibility of a relational database and SQL interface. One area to be aware of is that manual sharding (partioning your data across multiple databases to spread the load) is required if your database becomes large (~250GB) or hits limits around write or read throughput. This is the only database in the experiment which requires action at scale. The other databases are fully managed and scale automatically. Access to the database is via their javascript driver which you can use via a npm specifier or CDN (unpkg, esh.sh, etc). Though MySQL compatible, there are no foreign key constraints. Such constraints need to be implemented in application logic instead. Finally, when on the free tier only, your database will be put to sleep after 7 days of inactivity. You must manually wake it up via the console and until then it's completely inaccessible.

Performance: Across the regions, PlanetScale showed average to good write performance in comparison to the other databases in this experiment. However, transactions were very slow. Read performance was also surprisingly slow, slowest of all databases in the experiment (though, like DynamoDB, only one region was configured).

Consistency: PlanetScale's consistency model is eventual consistent.  Transactions are not ACID compliant. Strongly consistent reads are not supported.

Features/Flexibility: PlanetScale's standout feature is its schema management capabilities. It offers non-blocking schema changes, branching workflows (manage your production schema like you would with your code), and the ability to revert schema changes. Insights is another nice tool giving query level performance metrics.

Vendor independence: By being MySQL compatible, PlanetScale is perhaps the most vendor independent of the databases in the experiment. They additionally support the Airbyte open source data integration engine giving you an ETL path to move you data to another database.

Pricing: PlanetScale has some incredibly generous read/write pricing for it's database that puts it in a league of its own. The entry level paid plan gives you 100 billion (yes, billion) reads and 50 million writes. That's 850 times more reads per dollar spend than the next most cheapest database for reads (DynamoDB). On the flip side, while you also get 10GB storage free, after that the storage is very expensive compared to other databases (10x more expensive than Upstash or DynamoDB for example). However, many databases will stay under the free 10GB and so this may not be an issue.

Upstash Redis

MetricRating
Setup/Configuration★★★★★
Local development★★☆☆☆
Global distribution★★★★★
Ease of use★★★★☆
Performance★★★★☆
Consistency★★☆☆☆
Features/Flexibility★★★★☆
Vendor independence★★★★☆

Setup/Configuration: Upstash has a simple process to create a database through their UI console. You choose a name, global or regional configuration, primary region and read region(s) along with a few other options. Connection is maintained through a REST URL and token. Quick start guides are available for AWS Lambda, Vercel functions, Next.js, Fly.io, Deno Deploy and a fair few more. They are the only provider in this experiment other than KV to provide specific instructions for getting up and running on Deno Deploy.

Local development: Local development is achieved through a community supported project called Serverless Redis HTTP (SRH). While Upstash offer support to the maintenance they do not maintain this project and one concern would be the single maintainer of the project. SRH also has a few differences to Upstash Redis. Some instructions are provided for running SRH in docker, but there are gaps leaving you to fill in the blanks. Additionally you must install your own Redis server locally, for which no documentation or links are given. Compared to the other databases tested, Upstash Redis had the least robust local development experience.

Global distribution: Upstash provides 8 regions around the globe (3 US, 2 Europe, 1 Asia, 1 S. America, and 1 Australia) to use for primary and read replicas. As Upstash charge per 100k commands and each replica write consumes a command, adding additional read regions will increase your costs, how much depends on how write-heavy your application is.

Ease of use: Upstash was very easy to use with good documentation. For users with experience of Redis this will be a particularly easy database to use as Upstash Redis is Redis compatible. To get working with Deno Deploy, only a few imports and environment variables are needed.

Performance: While achieving 4 star performance, this is really a tale of two use cases. Write performance is sub-par (2 stars), while eventual read performance is excellent (5 stars), faster in almost every region than the other databases (N.B. remember that Upstash was configured with 8 read regions, while the others have 3 at most).

Consistency: A weak point of Upstash Redis is consistency. Their consistency model is eventual consistency. Additionally transactions, while supported in the API, are not ACID compliant.

Features/Flexibility: Upstash Redis is fairly feature rich. Some features include data eviction, encryption at rest, IP whitelisting and backup/restore amongst others.

Vendor independence: Like the other databases besides KV, Upstash Redis is portable and you can move it to another edge provider. Additionally, by using a Redis compatible API, you can in theory move to a different Redis installation. One challenge to that is there are little to no other offerings of globally distributed durable Redis.

Pricing: Upstash provides the simplest pricing model of the databases tested. With its serverless model, you only pay for what you use. That said, it also has the most expensive read/writes of the databases tested. Like DynamoDB global tables, the more read replicas you add the more expensive it becomes, linearly increasing your costs for writes and storage. Storage at least is very cheap, though unlike DynamoDB does not come with any free amount.

 

Final thoughts

The goal of this experiment was to put KV through its paces and compare it to other globally distributed database options for use on Deploy. Having done this, it is clear that KV is a serious contender and a very impressive database. The team appear to have made a great choice by using FoundationDB as the base to work on top of. With one of the strongest consistency models, some of the fastest performance and best in class ease of use, it's an obvious choice for many use cases.

In terms of individual databases, Fauna is talked highly of in technical circles and I can see its potential. However, I can't get away from its complexity. Developer time is expensive and unless Fauna really fit the project need, the cost of bringing the team up to speed with the database would be high. It's 'global' offering is also disappointing, though may improve in the future. Being limited to GraphQL API only (i.e. and not FaunaQL) on Deploy is also a potential drawback.

DynamoDB was one of the first serverless databases. Clearly it has proven itself and is a solid choice used by many companies large and small. To me, it feels like a database that has been around for a long time and is showing its age. It's highly performant, but has a mixed consistency model and the global tables feels like a bolt on rather than a core feature. Also, it was the only database in this experiment to incur a cold start penalty. That said, it's hard to beat it's enterprise features and AWS integrations. I found the lack of documentation on Deno usage very frustrating, though now that npm specifiers are supported in Deploy this should hopefully allow users to follow node based documentation.

PlanetScale was a surprise to me having heard great things about it. Technically it is impressive with Vitess and thus a sharded distributed relational database. Read performance is disappointingly slow. The need to manually shard your database once it degrades or runs into infrastructure problems is a turn off for me and runs counter to the serverless concept. Admittedly, few projects will ever need to undertake this. The schema management features are impressive and it's the definitive database in this experiment which can best handle relational data (N.B. Fauna also handles relational data and it would be interesting to pit these two against each other with complex scenarios around relational data). Finally, while storage is expensive, you get an astonishing amount of reads and writes for your money. If you use your database heavily with many reads/writes PlanetScale could make a very compelling case on price.

I loved how easy it was to get up and running with Upstash and those familiar with Redis will feel right at home. The simplicity of their serverless pricing model is really nice as well as the ability to customise replica regions. The pricing of reads and writes is expensive and so enabling lots of replicas could be costly. Write performance was also disappointing.

This leaves us with Deno KV. Going into this experiment, I didn't expect it to hold up as well as it has against the big hitters. Comparing to DynamoDB, it's as fast doing writes and faster doing reads thanks to replica regions (yes, it's not a fair comparison without enabling global tables in DynamoDB). Impressively, it achieves this with a stronger consistency model. The API is much easier to use than DynamoDB. It's also just such a joy to start coding with since there's nothing to install, setup, configure, etc. Whether you are coding for Deploy or locally, the KV database is just there waiting to be used. This will boost team creativity and productivity (less barriers) as well as reducing development costs. As a beta product, it's still lacking in a number of features. If you are already hosting on Deploy, using KV could be free if you stick within plan limits but pricing will quickly become much more expensive compared to other databases if you consistently read or write more than the plan limits.

Ultimately which database you choose will depend on your use case. If you need relational capabilities, go with PlanetScale or Fauna. If you need enterprise features or AWS integrations, DynamoDB is an solid choice. If read performance is critical, and you can tolerate eventual consistency, Upstash Redis may be your best choice. However, for many projects on Deploy, I would highly recommend KV.


Thank you for reading. I hope you found this experiment useful. If you have any questions, comments, or real world experience you want to share please reach out in the project discussions. Code for the experiment may also be found in the github repo.

Disclaimer:I have no affiliation with any of the companies mentioned in this article and am a first time user of each of the databases in the experiment.