AWS Glue vs Athena for Analytics Pipelines: A Practical Guide
In this article, let us compare AWS Glue and Amazon Athena and see where each service fits in an analytics pipeline. These services are often mentioned together because both work well with data in S3 and both use the Glue Data Catalog. But they solve different problems. Athena is mainly used to query data, while Glue is used to discover, prepare, and transform it.
For our use case, daily CSV files arrive in an S3 bucket. We want to clean those files, store the result as Parquet, and allow analysts to query the data using SQL. This is a small example, but it is close to how many data lake pipelines start.
The short answer
If the source data is already in a good format and you only need SQL queries, start with Athena. If you need repeatable transformations, schema handling, or Spark processing, use a Glue job. In many real projects the answer is not Glue or Athena. We use Glue to prepare the data and Athena to query the output.
| Requirement | Better fit | Why |
|---|---|---|
| Run ad-hoc SQL on S3 | Athena | No cluster or job code to manage |
| Convert CSV or JSON to Parquet | Glue | Spark jobs can transform and write at scale |
| Discover schemas and partitions | Glue crawler | Updates the Glue Data Catalog |
| Build dashboards over curated data | Athena | BI tools can query catalogued tables |
| Run complex reusable business logic | Glue | Easier to test and schedule as an ETL job |
Our example S3 layout
Assume an application places order files in the following location:
1
s3://demo-orders-raw/orders/year=2026/month=09/day=22/orders.csv
A file contains data like this:
order_id,customer_id,order_time,amount,status
1001,C101,2026-09-22T08:20:00Z,42.50,completed
1002,C102,2026-09-22T08:31:00Z,19.00,cancelled
We want the transformed files under s3://demo-orders-curated/orders/. The curated table should contain only completed orders, with amount stored as a decimal instead of a string.
Using Athena directly
We can create a table in Athena over the raw CSV data. Athena stores the table definition in the Glue Data Catalog even though we create it from the Athena query editor.
1
2
3
4
5
6
7
8
9
10
11
CREATE EXTERNAL TABLE raw_orders (
order_id bigint,
customer_id string,
order_time string,
amount decimal(12,2),
status string
)
PARTITIONED BY (year string, month string, day string)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES ('skip.header.line.count'='1')
LOCATION 's3://demo-orders-raw/orders/';
After creating the table, we need to make Athena aware of the partitions. For a quick demo, MSCK REPAIR TABLE raw_orders; scans the S3 prefixes and adds them. We can then query one day without scanning the entire bucket:
1
2
3
4
5
SELECT customer_id, sum(amount) AS total_amount
FROM raw_orders
WHERE year = '2026' AND month = '09' AND day = '22'
AND status = 'completed'
GROUP BY customer_id;
This is enough when the files are reliable and transformations are simple. We could also use an Athena CTAS query to produce Parquet:
1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE curated_orders
WITH (
format = 'PARQUET',
external_location = 's3://demo-orders-curated/orders/',
partitioned_by = ARRAY['year', 'month', 'day']
) AS
SELECT order_id, customer_id,
from_iso8601_timestamp(order_time) AS order_time,
amount, year, month, day
FROM raw_orders
WHERE status = 'completed';
For a one-time backfill this is convenient. The problem starts when we need validation, retries, incremental processing, or several transformation stages. SQL can still do much of it, but the pipeline becomes harder to operate as a collection of large scheduled queries.
Using an AWS Glue job
A Glue Spark job is a better fit when the transformation runs every day and we want job status, retries, and logs. A simplified PySpark script would look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, to_timestamp
spark = SparkSession.builder.getOrCreate()
source = "s3://demo-orders-raw/orders/year=2026/month=09/day=22/"
target = "s3://demo-orders-curated/orders/"
df = spark.read.option("header", True).csv(source)
clean = (
df.filter(col("status") == "completed")
.withColumn("order_id", col("order_id").cast("long"))
.withColumn("amount", col("amount").cast("decimal(12,2)"))
.withColumn("order_time", to_timestamp("order_time"))
)
(clean.write
.mode("append")
.partitionBy("year", "month", "day")
.parquet(target))
In a full script we would derive or pass the partition columns before writing. After the job writes Parquet, a Glue crawler can update the catalog table. Another option is to create the table and partitions through Terraform or an API call. I prefer managing stable table definitions as code because a crawler might infer a changed type when an unexpected file arrives. Crawlers are useful for discovery, but I would not depend on schema guessing for an important production table.
Athena can now query the curated table. Since Parquet is columnar and compressed, it normally scans much less data than CSV. That matters because Athena pricing is based mainly on bytes scanned.
How Glue and Athena work together
A practical flow would be:
- Files arrive in the raw S3 bucket.
- EventBridge or a workflow starts the Glue job.
- Glue validates the schema, removes invalid rows, and writes partitioned Parquet.
- The Glue Data Catalog stores the curated table definition.
- Athena queries the curated data for analysis or dashboards.
Glue is doing the pipeline work here. Athena is the query layer. The shared catalog is what makes the two services feel closely connected. We could also use Glue without Athena if another engine reads the Parquet files, and Athena without a Glue Spark job if the raw data is already usable.
Cost and operational differences
Athena is easy to start because there is no job infrastructure to configure. However, poorly filtered queries against CSV or unpartitioned data can become expensive. Always check the data scanned, use Parquet where possible, and include partition filters. Workgroups can enforce scan limits and keep query results in a controlled S3 location.
Glue jobs charge for the compute used while a job runs. Small jobs can still have startup overhead, so using Glue for every tiny SQL transformation might not be worth it. Job bookmarks can help process new data, but they are not a replacement for an idempotent design. A retry should not silently duplicate output files or rows.
There are also permissions to consider. The Glue job role needs access to the source, destination, catalog, logs, and possibly KMS keys. Athena users need access to the catalog, queried S3 locations, and query result bucket. Lake Formation can add table and column permissions, but it also adds another layer to troubleshoot.
What I would change for production
For a demo, hard-coded dates and MSCK REPAIR TABLE are fine. In production I would pass the processing date as a job argument, validate row counts, send bad records to a quarantine prefix, and publish metrics to CloudWatch. I would also compact small files because thousands of tiny Parquet files make both Spark and Athena slower.
The infrastructure should be deployed using Terraform or CloudFormation, including IAM roles, encryption, catalog databases, workgroups, and S3 lifecycle rules. For orchestration, Step Functions or an existing scheduler can start the Glue job and run data quality checks before making a partition available to users.
Conclusion
Athena is the simpler choice when data in S3 is ready to query and the work is mostly SQL. Glue is useful when data needs repeatable preparation, Spark transformations, or stronger job controls. For this example, I would use Glue to clean and convert the daily CSV files, then use Athena over the curated Parquet table. Keeping those responsibilities separate makes the pipeline easier to understand and operate.
