Build a Data Lake on S3

Khimananda Oli 6 min read Database
Build a Data Lake on S3

By Khimananda Oli | Last reviewed: August 2026

Teams often attempt to build a data lake on S3 by treating object storage as a simple file dump, only to face crippling query costs and unmanageable metadata later. A production-grade lake requires deliberate architectural choices around partitioning, format selection, and access governance before the first byte is ingested. This guide covers the infrastructure patterns I use to deploy scalable, cost-efficient analytics platforms that survive both rapid growth and compliance audits.

Data SourcesLogs / DBs / StreamsIngestion LayerETL / ValidationS3 Data LakeRaw ZoneCurated ZoneAnalytics ZoneGlue CatalogAthena / EMRSQL QueriesRedshift SpectrumBI Dashboards
Core zones and flow when you build a data lake on S3: raw ingestion, curated transformation, and governed consumption.

How do you structure partitions when you build a data lake on S3?

Partitioning is the single most impactful decision you make when you build a data lake on S3. Without it, every query scans the entire bucket, leading to timeouts and massive bills. The industry standard remains Hive-style partitioning because tools like Athena, Spark, and Trino understand it natively without extra configuration.

Hive-Compatible Key Design

Always prefix keys with the partition name followed by an equals sign. This allows crawlers to automatically infer schema and partition columns. Avoid deep nesting beyond three levels; excessive depth creates millions of tiny directories that degrade listing performance.

s3://my-analytics-lake/curated/events/
├── year=2026/
│   ├── month=08/
│   │   ├── day=14/
│   │   │   └── part-00000.parquet
│   │   └── day=15/
│   │       └── part-00000.parquet
└── year=2025/
    └── month=12/
        └── day=31/
            └── part-00000.parquet

Avoiding the Small Files Problem

S3 charges per request, and query engines struggle with thousands of kilobyte-sized files. If your ingestion rate is low, buffer writes or run periodic compaction jobs. For high-throughput streams, configure your writers to target file sizes between 128 MB and 1 GB. This range optimizes both S3 GET throughput and parallel scan efficiency in distributed SQL engines. You can manage these operational metrics effectively by integrating Prometheus metrics monitoring fundamentals into your pipeline observability stack.

  • Too small (<64MB): High request overhead, slow listing, excessive metadata memory usage.
  • Optimal (128MB–1GB): Balanced parallelism, efficient compression, minimal API costs.
  • Too large (>5GB): Reduced parallelism, longer retry times on failure, memory pressure during reads.

What storage formats and lifecycle policies reduce S3 data lake costs?

Format choice dictates query speed and storage footprint. Row-based formats like CSV or JSON are human-readable but terrible for analytics. When you build a data lake on S3 for reporting or ML, always default to columnar formats.

FormatCompressionQuery PerformanceBest Use Case
ParquetSnappy / GZIPExcellent (columnar)General analytics, Athena, Spark
ORCZLIB / SnappyExcellent (columnar)Hive-heavy ecosystems, ACID transactions
AvroDeflate / SnappyModerate (row-based)Kafka streaming, schema evolution
JSON LinesGZIPPoorRaw landing zone only

Automating Tier Transitions

Data lakes accumulate petabytes over time. Most data loses value after 90 days but must be retained for compliance. Configure S3 Lifecycle Rules immediately upon creation. Moving objects to Intelligent-Tiering or Glacier Flexible Retrieval prevents storage costs from dominating your AWS bill. As discussed in cloud cost optimization tactics, automated tiering is often the highest-ROI change for mature lakes.

{
  "Rules": [
    {
      "ID": "LakeTieringPolicy",
      "Status": "Enabled",
      "Filter": { "Prefix": "curated/" },
      "Transitions": [
        { "Days": 90, "StorageClass": "INTELLIGENT_TIERING" },
        { "Days": 365, "StorageClass": "GLACIER" }
      ]
    },
    {
      "ID": "RawCleanup",
      "Status": "Enabled",
      "Filter": { "Prefix": "raw/" },
      "Expiration": { "Days": 730 }
    }
  ]
}
S3 StandardDays 0–90Hot / Active QueriesIntelligent-TieringDays 91–365Auto-optimized AccessGlacier FlexibleDay 365+Compliance Archive90 Days365 DaysLifecycle Rule Engine
Cost-efficient tiering strategy essential when you build a data lake on S3 for long-term retention.

How do you secure and govern access in an S3 data lake?

Security cannot be retrofitted. In my experience helping teams achieve SOC 2 and ISO 27001 compliance, the most common audit finding in data lakes is overly permissive bucket policies. When you build a data lake on S3, assume every object is sensitive until proven otherwise.

Encryption and Key Management

Enable server-side encryption with AWS KMS (SSE-KMS) at the bucket level. This provides envelope encryption and detailed CloudTrail audit logs for every decrypt operation. For regulated industries in Nepal or globally, customer-managed keys (CMKs) demonstrate control during audits. Never use SSE-S3 for production analytics if you require key rotation or access logging.

Least-Privilege Bucket Policies

Deny unencrypted uploads and non-TLS requests explicitly. Combine this with IAM roles scoped to specific prefixes rather than wildcards.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnencryptedObjectUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-analytics-lake/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "aws:kms"
        }
      }
    },
    {
      "Sid": "EnforceTLSOnly",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-analytics-lake",
        "arn:aws:s3:::my-analytics-lake/*"
      ],
      "Condition": {
        "Bool": { "aws:SecureTransport": "false" }
      }
    }
  ]
}

For deeper guidance on securing credentials and managing secrets across your platform, review Kubernetes secrets management done right, as similar principles apply to IAM role chaining and cross-account access.

How does AWS Glue Catalog integrate with S3 data lakes?

Without a metastore, your S3 lake is just files. AWS Glue Catalog acts as the central metadata repository, enabling SQL queries without manual schema definition. It decouples storage from compute, allowing Athena, EMR, and Redshift Spectrum to share a single source of truth.

Crawler Configuration Best Practices

Crawlers can be expensive if misconfigured. Schedule them incrementally after ETL jobs complete rather than running continuously. Exclude temporary directories and set classifiers explicitly for custom formats. For Parquet and ORC, crawlers read footers efficiently; for CSV, they sample rows which can fail on heterogeneous schemas.

  1. Create separate databases for each environment (dev, staging, prod) to prevent accidental cross-contamination.
  2. Use table properties to tag PII columns, enabling fine-grained row/column filtering via Lake Formation.
  3. Enable partition projection for high-cardinality dimensions to avoid crawler overhead entirely.
  4. Version your Glue schemas alongside your Terraform code to ensure reproducible deployments.
S3 Bucketsraw/ (JSON)curated/ (Parquet)analytics/ (ORC)AWS Glue CatalogCentral MetastoreSchema RegistryPartition IndexAmazon AthenaServerless SQLRedshift SpectrumDW FederationCrawl / RegisterMetadata APIExternal Tables
Glue Catalog serves as the unified metadata layer enabling multiple engines to query S3 consistently.

Build a Data Lake on S3 That Scales Safely

Building a functional prototype takes hours; building one that survives production takes discipline. Start with strict partitioning, enforce encryption and TLS from day one, and automate lifecycle transitions before costs spiral. Treat your data lake as engineered infrastructure, not ad-hoc storage. If your team needs help designing a compliant, cost-effective architecture or auditing an existing deployment, reach out to discuss your data platform requirements.

Frequently Asked Questions

Use S3 Standard for active ingestion and query layers. Transition raw historical data to S3 Intelligent-Tiering automatically after 30 days using lifecycle policies to optimize costs without manual intervention or performance penalties during unexpected access spikes in 2026 architectures.

Adopt Hive-style partitioning like s3://bucket/table/year=2026/month=08/. This structure enables partition pruning in Athena and Spark, drastically reducing scan costs. Avoid deep nesting beyond three levels and never use random prefixes that prevent efficient listing operations during large-scale analytical queries.

Yes. Use Apache Iceberg or Delta Lake directly on S3 with open-source catalogs like Nessie or AWS SDKs. Skip Glue if you prefer managing metadata externally or want vendor neutrality, though you lose native AWS integration benefits and automated schema detection features.

Parquet is optimal for columnar analytics due to compression and predicate pushdown support. Use Avro only for write-heavy ingestion pipelines requiring schema evolution. Avoid CSV or JSON for production analytical workloads as they lack binary encoding, statistics, and efficient partial read capabilities needed for cost-effective querying.

Costs vary by volume but expect $0.023 per GB stored plus request fees. A 10TB lake with moderate queries typically runs $300-$500 monthly including Athena scans. Enable Intelligent-Tiering and compress files to reduce storage expenses significantly compared to keeping all data in standard storage tiers.

S3 Table Buckets simplify ACID transactions and metadata management natively. Choose them over regular buckets if you need built-in table semantics without external catalogs. Regular S3 remains better for unstructured blobs or when integrating with diverse compute engines outside the AWS ecosystem in 2026.

Enable server-side encryption with SSE-KMS and apply bucket policies denying unencrypted uploads. Use VPC endpoints to keep traffic private. Implement row-level security via Lake Formation or Iceberg ACLs. Never store PII in plaintext; use client-side encryption or tokenization before ingestion.

Small files cause excessive metadata overhead. Run OPTIMIZE or compaction jobs to merge files into 128-256MB chunks. Ensure partition keys align with query filters. Check CloudWatch for scanned bytes; high values indicate missing partitions or inefficient formats requiring conversion to compressed Parquet with proper sorting.

Not strictly required but highly recommended. Catalogs track schemas, partitions, and lineage across teams. Without one, developers manually manage paths and formats causing drift. AWS Glue, Unity Catalog, or Apache Polaris provide governance essential for multi-team environments scaling beyond single-user experimental projects in production systems.

Use open table formats like Apache Iceberg supporting additive and compatible schema changes. Store schemas in a central registry. Configure readers to fail safely on incompatible types. Test migrations in staging first. Avoid overwriting existing data; append new versions instead to maintain backward compatibility for downstream consumers.

Yes, configure S3 Event Notifications to invoke Lambda for lightweight transformations under 15 minutes. For heavier workloads, have Lambda start Step Functions or Batch jobs. Avoid processing large files directly in Lambda due to memory limits; use it only for orchestration or small-file validation tasks.

S3 stores raw structured and unstructured data cheaply with flexible schemas. Warehouses like Redshift optimize for fast SQL on curated datasets. Lakes handle ingestion and exploration; warehouses serve BI dashboards. Modern architectures combine both using lakehouse patterns where S3 backs transactional tables queried through warehouse engines.

Enable S3 Storage Lens for usage trends and CloudWatch metrics for request latency. Set alarms on 4xx/5xx errors indicating permission or throttling issues. Track Athena query runtime and scanned bytes daily. Audit access logs via CloudTrail to detect unauthorized reads or anomalous patterns across your lake.

Versioning protects against accidental deletes but increases storage costs exponentially. Enable it only on critical metadata or configuration objects. For bulk data, rely on immutable writes, snapshots in Iceberg, or cross-region replication instead. Restore individual versions programmatically rather than browsing console UIs at scale.

Use AWS DataSync or DistCp for parallel transfers preserving directory structures. Convert legacy ORC/Avro to Parquet post-migration. Update Hive metastore pointers to S3 URIs. Validate row counts and checksums. Plan cutover during low-traffic windows and retain on-prem backups until verification completes successfully across all datasets.