PlanetScale’s pricing model, while seemingly straightforward with its "rows read" and "rows written" metrics, can feel like a black box if you don’t understand the underlying mechanics and how your application’s data access patterns directly translate into costs. It’s less about how many rows your database stores and more about how many rows your database processes for your application’s queries.

Let’s see this in action with a hypothetical e-commerce platform. Imagine a simple product listing page that displays 20 products.

-- Query to fetch products for a listing page
SELECT id, name, price, image_url
FROM products
WHERE category_id = 123
LIMIT 20;

If the products table has 10,000 rows, and this query is executed, PlanetScale might read significantly more than 20 rows internally. A typical database would scan the products table, potentially reading every single row to find the ones matching category_id = 123. Even with an index on category_id, the database might still read several hundred rows to satisfy the WHERE clause before applying the LIMIT 20.

On PlanetScale, this query, depending on indexing and the actual data distribution, could result in, say, 500 rows read. If this page is viewed 10,000 times a day, that’s 5,000,000 rows read. Multiply that by your cost per million rows read, and you can see how quickly this accrues.

Now consider a write operation: updating the stock of a product after a purchase.

-- Query to update product stock
UPDATE products
SET stock = stock - 1
WHERE id = 456;

This query, assuming id is the primary key and thus indexed, is highly efficient. It directly locates the row for product ID 456 and modifies it. This would likely result in 1 row written. This is generally much cheaper than reads, but high-volume write operations can still add up.

The core problem PlanetScale’s pricing solves is the traditional cloud database model where you pay for provisioned resources (CPU, RAM, storage) regardless of actual usage. This often leads to over-provisioning and wasted spend for applications with spiky or low-usage patterns. PlanetScale’s usage-based pricing aims to align costs directly with the value derived from the database.

Understanding the "rows read" and "rows written" metrics requires grasping how your queries interact with your database schema and indexes. A SELECT * FROM users query on a table with a million users will, by default, read a million rows. If that query is not properly filtered or indexed, it’s a massive cost driver. Conversely, a query that uses a highly selective index and returns a single row will be very inexpensive.

The actual number of rows read for a given query isn’t just the number of rows returned. It’s the number of rows the database examines to find the data you requested. For SELECT statements, this includes rows scanned to satisfy WHERE clauses, JOIN conditions, and GROUP BY clauses, before the final result set is formed. For UPDATE and DELETE statements, it’s the number of rows that match the WHERE clause and are then modified or removed. INSERT statements count as 1 row written per row inserted.

The most surprising aspect for many users is how much reads can dwarf writes in terms of cost, especially with poorly optimized queries. An application might perform thousands of writes per day, which might seem like a lot, but if it performs hundreds of thousands of reads for simple data retrieval or reporting that could be optimized, the read cost can easily become the dominant factor. For instance, a dashboard that aggregates data by repeatedly scanning large tables without proper indexing or materialized views can incur enormous read costs.

The next concept you’ll likely grapple with is how to effectively monitor and optimize these costs, which leads into understanding query performance and indexing strategies within PlanetScale.

Want structured learning?

Take the full Planetscale course →