Free DVA-C02 practice test

20 questions for the AWS Developer Associate (DVA-C02) exam, taken from our 205-question bank and spread across its 3domains by their weighting. No sign-up needed: pick an answer to check it, or open “Show answer & explanation” under any question.

This exam retires on November 30, 2026.

November 30, 2026 is the last day to take DVA-C02. DVA-C03 registration opens October 27, 2026 and general availability begins December 1, 2026. AWS says DVA-C03 validates AI-assisted development workflows and modern security practices for AI services; take DVA-C02 before the cut-off if you are already prepared.

What this test covers

Question 1 · Development with AWS Services

A developer is designing an Amazon DynamoDB table for a social media application. Users can follow other users and see a personalized feed of posts. The access patterns are: (1) get all posts by a specific author, sorted by timestamp descending; (2) get a single post by its unique post ID. Which primary key design BEST supports both access patterns efficiently?

Show answer & explanation

Correct answer: A

  • A. Partition key: postId (UUID). Add a GSI with partition key: authorId and sort key: timestamp.

Option A uses a UUID postId as the partition key of the base table, enabling O(1) GetItem lookups for access pattern 2. A GSI with authorId as partition key and timestamp as sort key directly supports access pattern 1—querying by author and sorting by time descending with no extra reads. Option B makes the base table's partition key authorId with sort key timestamp, which handles access pattern 1 natively, but retrieving a single post by postId requires a GSI on postId—however, a GSI on a non-key attribute only supports Query (with an equality filter on the partition key), not a direct GetItem, adding slight inefficiency compared to option A's base table GetItem. More critically in option B the GSI would have postId as its partition key but no sort key, meaning you'd get a single item per partition which is fine, but the base table choice of authorId+timestamp makes it hard to have a truly unique single-key lookup without the GSI. Option A is still cleaner overall. Option C uses a LSI (sort key: timestamp) on a base table keyed by authorId+postId; LSIs must share the same partition key as the base table, so you can query by authorId and sort by timestamp via the LSI—but you cannot do a direct single-item lookup by postId alone without knowing the authorId, making access pattern 2 incomplete. Option D uses Scan with FilterExpression to retrieve posts by author, which is extremely inefficient and costly on large tables and is an anti-pattern.

Question 2 · Development with AWS Services

An e-commerce application uses Amazon SQS to decouple order placement from order fulfillment. A consumer application processes each message and calls a third-party payment API that occasionally takes up to 8 minutes to respond. The operations team reports that orders are being processed twice. Which configuration change BEST resolves the duplicate processing issue?

Show answer & explanation

Correct answer: C

  • C. Increase the SQS visibility timeout to a value greater than 8 minutes (e.g., 10 minutes).

When a consumer receives a message, SQS hides it for the duration of the visibility timeout. If the consumer doesn't delete the message before the timeout expires, SQS makes it visible again and another consumer can receive it—causing duplicate processing. Because the payment API can take up to 8 minutes, the visibility timeout must exceed that (e.g., 10 minutes) so the original consumer has time to finish and delete the message. — Long polling (A) reduces empty receives and API calls but has no effect on visibility timeout or duplicate delivery. FIFO queues (B) offer exactly-once processing at the API level (deduplication ID), but if the visibility timeout is still too short the message will still reappear and be delivered again; the root cause here is the timeout, not ordering. Decreasing the retention period (D) would cause messages to be deleted before they're processed at all, resulting in lost orders rather than duplicates.

Question 3 · Development with AWS Services

A company's application sends order confirmation emails through Amazon SNS. Recently, a compliance requirement was added: marketing messages must only be sent to subscribers who have opted into the 'promotions' category, while transactional messages must go to all subscribers. Both message types are published to the same SNS topic. What is the MOST cost-effective SNS feature to implement this routing without creating separate topics?

Show answer & explanation

Correct answer: A

  • A. SNS Message Filtering using subscription filter policies to route messages based on message attributes.

SNS subscription filter policies allow each subscription endpoint to declare which message attributes it wants to receive. By tagging published messages with an attribute like messageType=promotional or messageType=transactional, only the subscriptions with matching filter policies receive each message. This achieves the routing requirement on a single topic with no additional infrastructure. — SNS FIFO topics (B) are designed for ordered, deduplicated delivery—they don't solve the content-based routing problem between subscriber groups. An SQS/Lambda re-publishing pattern (D) works functionally but introduces unnecessary extra services, complexity, and cost when SNS natively supports this with filter policies. DLQs (C) are for capturing failed deliveries; they cannot be used to selectively deliver messages to opted-in subscribers.

Question 4 · Development with AWS Services

A developer is using Amazon EventBridge to route events between microservices. A new requirement states that events from an external partner's AWS account must be received on the company's event bus and processed by a Lambda function. Which steps are required to enable cross-account event delivery? (Select TWO)

Select 2 answers.

Show answer & explanation

Correct answers: A, D

  • A. Add a resource-based policy to the company's custom event bus granting the partner account permission to put events.
  • D. In the partner account, create an EventBridge rule with the company's custom event bus ARN as the target.

Cross-account EventBridge event delivery requires two steps: (1) The receiving account must add a resource-based policy to its custom event bus that explicitly grants the sending account (or organization) permission to call events:PutEvents on that bus—this is option A. (2) In the sending (partner) account, an EventBridge rule must be created with a target pointing to the receiving account's custom event bus ARN, so matching events in the partner account are forwarded—this is option D. VPC peering (C) is irrelevant; EventBridge is a managed AWS service that communicates over the AWS backbone, not through customer VPCs. AWS PrivateLink (B) provides private connectivity to EventBridge within a VPC but is not required for cross-account event delivery—event bus policies handle authorization. An IAM role assumption model (E) is used for cross-account API calls via the AWS SDK, not for EventBridge cross-account routing; the correct mechanism is event bus resource-based policies combined with EventBridge rules.

Question 5 · Development with AWS Services

A developer is building a serverless application where an AWS Lambda function must be invoked every weekday at 08:00 UTC to generate a daily business report. The function should NOT be triggered on weekends. Which Amazon EventBridge configuration achieves this requirement?

Show answer & explanation

Correct answer: A

  • A. Create an EventBridge rule with a cron expression: cron(0 8 ? * 2-6 *).

EventBridge cron expressions use the format cron(Minutes Hours Day-of-month Month Day-of-week Year). cron(0 8 ? * 2-6 *) fires at 08:00 UTC on days 2–6 (Monday through Friday), with '?' used in the day-of-month field because day-of-week is specified — exactly the requirement. Option B rate(1 day) triggers every 24 hours regardless of which day it falls on, including weekends. Option D cron(0 8 * * MON-FRI ) is syntactically invalid for EventBridge because you cannot specify both day-of-month () and day-of-week (MON-FRI) simultaneously; one must be '?'. Option C a 5-day rate will drift and does not reliably target weekdays only.

Question 6 · Development with AWS Services

A developer is building a mobile application backend using AWS AppSync. The application requires a GraphQL mutation that writes user profile data to Amazon DynamoDB. After deploying the AppSync API, the developer finds that the mutation returns data successfully in the AppSync console test, but when called from the mobile app the mutation returns an 'Unauthorized' error. The AppSync API uses Amazon Cognito User Pools as the authorization mode. What is the MOST likely cause?

Show answer & explanation

Correct answer: A

  • A. The mobile app is not including a valid Cognito User Pool JWT token in the Authorization header of the GraphQL request.

When AppSync is configured with Cognito User Pools authorization, every GraphQL request must include a valid JWT access token (or ID token) in the Authorization header. The AppSync console test uses the developer's own authenticated session, so it succeeds. The mobile app failing with 'Unauthorized' almost always means the app is not attaching the Cognito JWT — either the user is not signed in, the token is expired, or the SDK is not configured to pass the token. Option C resolver template syntax errors would produce mapping errors or data errors, not an 'Unauthorized' response; they would also appear in the console test. Option B AppSync accesses DynamoDB through the API's IAM service role, not a resource-based policy on the table; a permissions failure here would surface as a different error type (not Unauthorized to the client). Option D if Cognito User Pools were not configured as an authorization mode at all, the console test would also fail — the fact that the console succeeds means the authorization mode is correctly set up on the API side.

Question 7 · Development with AWS Services

An application uses AWS Step Functions to process insurance claims. Each claim goes through validation, fraud-check, and payment steps. The fraud-check step calls a third-party API that occasionally returns HTTP 429 (Too Many Requests) errors. The developer wants the workflow to automatically retry the fraud-check step with exponential backoff before failing the claim. Which Step Functions configuration achieves this?

Show answer & explanation

Correct answer: B

  • B. Add a Retry block on the fraud-check state specifying the error type, MaxAttempts, IntervalSeconds, and BackoffRate.

Step Functions states support a Retry field that takes a list of retriers, each specifying ErrorEquals (e.g., Lambda.TooManyRequestsException or a custom error), MaxAttempts, IntervalSeconds (initial wait), and BackoffRate (multiplier per retry). This is the native, purpose-built mechanism for automatic exponential backoff retries within a workflow. A Catch block (A) is for transitioning to a different state after all retries are exhausted or for handling errors in a fallback path—it does not perform retries; it moves execution to another state. Express Workflows (C) differ from Standard Workflows in execution duration and pricing characteristics but do NOT automatically add retry logic to states; retries must still be explicitly configured with a Retry block. Implementing retry logic inside the Lambda function itself (D) is an anti-pattern when using Step Functions—it conflates orchestration concerns with business logic, and sleeping inside a Lambda function wastes execution time and cost; the retry should be managed by the orchestrator.

Question 8 · Development with AWS Services

A developer is designing an Amazon DynamoDB table for a blog platform. Each blog post belongs to one author and can have many comments. The most common access pattern is retrieving all comments for a specific blog post, sorted by the time the comment was posted. Which table design BEST supports this access pattern?

Show answer & explanation

Correct answer: B

  • B. Use postId as the partition key and commentTimestamp as the sort key on the base table.

Using postId as the partition key groups all comments for a post together, and using commentTimestamp as the sort key allows efficient range queries sorted by time with a single Query call. This directly models the described access pattern. — Using postId as partition key and commentId as sort key groups comments per post but requires filtering to sort by time; commentId (often a UUID) is not time-ordered. — Using authorId as the partition key groups items by author, not by post, making it inefficient to retrieve comments for a specific post. — Using commentId alone as the partition key scatters comments across partitions; the GSI would allow queries by post, but comments are not natively sorted by timestamp without adding a sort key to the GSI projection.

Question 9 · Security

A developer is designing the trust policy for an IAM role that will be assumed by an Amazon EC2 instance in the same AWS account. Which trust policy correctly allows EC2 to assume the role?

Show answer & explanation

Correct answer: C

  • C. { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" }

Option C is correct. An EC2 instance profile assumes a role using the EC2 service principal "ec2.amazonaws.com" with the sts:AssumeRole action. This trust policy statement is placed in the role's trust policy (not the permission policy) and allows the EC2 service to assume the role on behalf of the instance. Option B is incorrect because using the account root ARN as the principal allows any IAM entity in the account to assume the role (if they also have an identity-based policy allowing it), which is overly permissive and not specific to EC2. Option A is incorrect because the "Federated" principal type is used for web identity or SAML federation (e.g., Cognito, Google), not for EC2 service principals; additionally, sts:AssumeRoleWithWebIdentity is for federated web identity, not EC2 instance profiles. Option D is incorrect because lambda.amazonaws.com is the service principal for Lambda functions, not EC2 instances; using this would allow Lambda to assume the role, not EC2.

Question 10 · Security

A developer needs to grant a third-party AWS account (Account B) permission to read objects from an Amazon S3 bucket owned by Account A. The bucket has Block Public Access enabled. Which combination of steps is required? (Select TWO)

Select 2 answers.

Show answer & explanation

Correct answers: A, C

  • A. Add a bucket policy in Account A that allows s3:GetObject for the Account B principal
  • C. Grant the IAM principal in Account B an identity-based policy that allows s3:GetObject on the Account A bucket

Options A and C are correct. For cross-account S3 access without role assumption, both the resource-based policy (bucket policy in Account A) AND the identity-based policy (in Account B) must grant access. Account A's bucket policy must explicitly allow Account B's principal to perform s3:GetObject, and Account B's IAM user or role must have an identity-based policy allowing s3:GetObject on the Account A bucket. Both sides must agree. Option B is incorrect because creating an IAM role with a cross-account trust policy is an alternative approach (role assumption), not a complement to the direct bucket policy approach; the question scenario does not indicate role assumption is needed. Option D is incorrect because Block Public Access controls public access (anonymous requests) and does not affect authenticated cross-account access; disabling it would be a security risk and is unnecessary. Option E is incorrect because presigned URLs are a per-object workaround that do not constitute a scalable access control solution and expire; they are not the standard mechanism for ongoing cross-account bucket access.

Question 11 · Security

A developer is using AWS KMS to implement envelope encryption for data stored in Amazon S3. The application calls GenerateDataKey to get a plaintext data key and an encrypted data key. Which of the following statements correctly describes the security model the developer should follow when storing data?

Show answer & explanation

Correct answer: D

  • D. Store the encrypted data key alongside the encrypted data in S3; discard the plaintext data key from memory after encryption

Correct (D): In envelope encryption, the plaintext data key is used to encrypt the data and must then be immediately discarded from memory. The encrypted data key (the envelope) is safe to store alongside the ciphertext because it can only be decrypted by calling KMS with appropriate permissions. To decrypt, the application retrieves the encrypted data key, calls kms:Decrypt to recover the plaintext key, decrypts the data, and discards the plaintext key again. Wrong (A): Storing the plaintext data key defeats the entire purpose of envelope encryption; if an attacker accesses S3, they gain the ability to decrypt all data. Wrong (B): Storing plaintext keys in Parameter Store (even SecureString) is not the correct envelope encryption model; the plaintext key should never be persisted anywhere. Wrong (C): Re-using a single data key for all objects increases blast radius; if that key is ever exposed, all objects are compromised. Best practice is to use a unique data key per object or per encryption operation.

Question 12 · Security

A developer is building a serverless application where an AWS Lambda function needs to access a secret stored in AWS Secrets Manager. During testing, the function returns an AccessDeniedException even though the function's execution role has the secretsmanager:GetSecretValue action allowed. The secret was created with a customer-managed KMS key (CMK). What is the MOST likely cause of the error?

Show answer & explanation

Correct answer: B

  • B. The Lambda execution role lacks the kms:Decrypt permission on the CMK used to encrypt the secret

Correct (B): When a secret is encrypted with a customer-managed KMS key, retrieving the secret value requires two permissions: secretsmanager:GetSecretValue on the secret AND kms:Decrypt on the CMK. If only the Secrets Manager permission is present, the KMS decryption step fails, resulting in an AccessDeniedException. Wrong (A): A missing VPC endpoint would cause a network connectivity error (timeout or connection refused), not an AccessDeniedException. Wrong (C): While a resource-based deny policy would also cause an AccessDeniedException, the question states secretsmanager:GetSecretValue is already allowed; the more likely gap is the KMS permission, which is the most common oversight in this specific scenario. Wrong (D): secretsmanager:DescribeSecret returns metadata only (no secret value) and is not required to call GetSecretValue.

Question 13 · Security

A developer is implementing a Lambda authorizer (TOKEN type) for an Amazon API Gateway REST API. During load testing, the team notices that the authorizer Lambda is invoked on every single request, adding significant latency. The authorization decisions do not change frequently. What should the developer do to reduce latency and cost?

Show answer & explanation

Correct answer: A

  • A. Enable authorizer result caching on the Lambda authorizer and set an appropriate TTL

Option A is correct. API Gateway Lambda authorizers support a built-in authorization caching mechanism. When enabled, API Gateway caches the IAM policy returned by the authorizer for a configurable TTL (up to 3600 seconds), keyed on the incoming token (for TOKEN type) or request parameters (for REQUEST type). This eliminates repeated Lambda invocations for the same token, reducing both latency and cost. Option B is incorrect because switching to a REQUEST authorizer does not add automatic caching; caching must be explicitly enabled on either authorizer type. Option C is incorrect because adding ElastiCache is a much more complex and expensive operational solution when API Gateway's native caching already solves the problem. Option D is incorrect because migrating to a Cognito authorizer changes the authentication mechanism entirely and may not be applicable; moreover, the question asks about optimizing the existing Lambda authorizer setup.

Question 14 · Security

A developer is implementing AWS STS in an application that runs on Amazon EC2. The application needs to access resources in a second AWS account (Account B). The developer has created an IAM role in Account B with a trust policy. Which STS API call should the EC2 instance's application use to obtain temporary credentials to access Account B resources?

Show answer & explanation

Correct answer: C

  • C. sts:AssumeRole

Correct (C): sts:AssumeRole is the correct API for cross-account access. The calling identity (the EC2 instance's role) assumes the role in Account B, and STS returns temporary security credentials scoped to that role. The Account B trust policy must list Account A's role or account as a trusted principal. Wrong (A): sts:GetSessionToken is used to obtain temporary credentials for an IAM user, typically to enable MFA for API calls; it does not allow assuming a role in another account. Wrong (B): sts:AssumeRoleWithWebIdentity is used when the caller is authenticated by an external web identity provider (e.g., Cognito, Google, Facebook), not for standard EC2-to-cross-account role assumption. Wrong (D): sts:GetFederationToken is used to create temporary credentials for federated users (e.g., via a custom identity broker); it does not assume a specific IAM role and is not intended for cross-account service-to-service access.

Question 15 · Security

A developer is using AWS Systems Manager Parameter Store to store a database connection string as a SecureString parameter encrypted with a KMS Customer Managed Key (CMK). An EC2 instance needs to retrieve this parameter. The EC2 instance has an IAM role with ssm:GetParameter permission on the parameter ARN. However, the API call returns an AccessDeniedException. What is the most likely missing permission?

Show answer & explanation

Correct answer: B

  • B. The EC2 instance role needs kms:Decrypt permission on the CMK used to encrypt the SecureString parameter

When retrieving a SecureString parameter from Parameter Store, AWS SSM internally calls KMS to decrypt the parameter value before returning it. If the calling IAM principal does not have kms:Decrypt permission on the CMK, the decryption fails and SSM surfaces an AccessDeniedException. The EC2 role already has ssm:GetParameter, so the SSM permission is not the issue. ssm:DescribeParameters is for listing/searching parameters and is not required to retrieve a specific parameter by name. ssm:GetParametersByPath is an alternative API for path-based retrieval; SecureString parameters can be fetched with ssm:GetParameter. The last option describes an explicit Deny scenario, which is not stated in the problem — the most likely cause given the setup is simply the missing kms:Decrypt permission.

Question 16 · Deployment

A developer is working with AWS CloudFormation and needs to update a stack. Before applying the update, they create a change set to preview the changes. The change set shows that an RDS DB instance will be replaced (Action: Replace, Replacement: True). The developer is concerned about data loss. What does 'Replacement: True' indicate in a CloudFormation change set, and what should the developer do to prevent data loss?

Show answer & explanation

Correct answer: C

  • C. It means CloudFormation will delete the existing DB instance and create a new one. The developer should take a manual snapshot before applying the change set.

In a CloudFormation change set, 'Replacement: True' means that the resource will be deleted and a new resource will be created in its place. For a stateful resource like an RDS DB instance, this means the existing database instance will be deleted (along with all its data unless a final snapshot is taken or deletion protection is enabled). The developer must take a manual DB snapshot before executing the change set to preserve data. They should also consider setting DeletionPolicy: Snapshot on the DB instance resource in the template to ensure CloudFormation takes a snapshot before deletion. — Option B is incorrect because 'Replacement: True' explicitly means the resource will be replaced (deleted and recreated), not modified in place. Option E is incorrect because replacement is triggered by a template change that requires a new physical resource, not by drift detection; drift reconciliation is a separate concept. Option A is incorrect because CloudFormation does not perform a zero-downtime blue/green-style replacement for RDS instances; the old instance is deleted, resulting in data loss if not backed up. Option D is incorrect because 'Replacement: True' in a change set indicates resource replacement, not a pending modification requiring a maintenance window.

Question 17 · Deployment

A developer is deploying an AWS SAM application that includes an Amazon SQS queue triggering a Lambda function. The developer wants to test the SQS-to-Lambda integration locally before deploying to AWS. Which command and approach is MOST appropriate for this local testing scenario?

Show answer & explanation

Correct answer: B

  • B. Run sam local invoke with a synthetic SQS event JSON file using the --event flag to simulate the SQS trigger locally.

sam local invoke with a synthetically crafted SQS event JSON file is the correct and standard way to test SQS-triggered Lambda functions locally. You model the SQS Records payload structure and pass it with --event events/sqs-event.json. AWS SAM CLI documentation explicitly provides example SQS event payloads for this purpose. Option A is incorrect because actual AWS SQS cannot route messages to a local machine endpoint — SQS pulls Lambda on the AWS side and cannot reach localhost. Option D is incorrect; sam local start-api only simulates API Gateway HTTP triggers. It does not start or simulate SQS, SNS, DynamoDB Streams, or other event sources. Option C is not local testing — it deploys to AWS and uses CloudWatch Logs, which defeats the purpose of local testing.

Question 18 · Deployment

A developer is using .ebextensions to configure an Elastic Beanstalk environment. They add the following configuration file:

# .ebextensions/security.config
option_settings:
  aws:elasticbeanstalk:environment:proxy:
    ProxyServer: nginx
container_commands:
  01_set_header:
    command: "echo 'add_header X-Frame-Options DENY;' >> /etc/nginx/conf.d/elasticbeanstalk/00_application.conf"

After deploying, the developer notices the header is not present in responses. What is the MOST LIKELY cause?

Show answer & explanation

Correct answer: D

  • D. Nginx must be reloaded after modifying its configuration files, and container_commands does not automatically trigger a reload

The container_commands in .ebextensions run after the application source is extracted and set up, but after they complete, the Nginx service is not automatically reloaded. The echo appends content to the config file, but Nginx continues serving with its previously loaded configuration until it is restarted or reloaded. The developer must add a services block in .ebextensions to ensure Nginx restarts when the config file changes, or add a command to explicitly reload Nginx. — Option A is incorrect because container_commands run after the source is deployed and the nginx directory already exists. Option B is incorrect because container_commands run as root by default (unless test overrides), so permission is not the issue. Option E is incorrect because Elastic Beanstalk configuration files must use the .config extension; .cfg would not work. Option C is incorrect because aws:elasticbeanstalk:environment:proxy with ProxyServer: nginx is a valid namespace option.

Question 19 · Deployment

A developer is using AWS CDK to define an S3 bucket with versioning enabled and a lifecycle rule that transitions objects to S3 Glacier after 90 days. After running cdk deploy, the developer modifies the lifecycle rule to transition after 60 days instead. What happens when the developer runs cdk deploy again?

Show answer & explanation

Correct answer: A

  • A. CDK detects the change and updates the S3 bucket's lifecycle configuration in place without replacing the bucket

S3 bucket lifecycle configurations can be updated in place via CloudFormation (which CDK synthesizes to). Modifying a lifecycle rule is not a property that requires resource replacement; CloudFormation will issue an update to the existing bucket's lifecycle configuration. CDK detects the diff between the current deployed state and the new synthesized template, then applies the delta update without destroying the bucket. — Option D is incorrect because S3 lifecycle rule changes do not trigger bucket replacement in CloudFormation. Option C is incorrect because S3 lifecycle rules are not immutable; they can be added, modified, or deleted at any time, and CDK/CloudFormation does not add a manual confirmation step for this type of change. Option E is incorrect because cdk deploy is idempotent and can be run multiple times on the same stack. Option B is incorrect because CDK by default does not require manual approval for lifecycle rule changes; approval gates must be explicitly configured in a pipeline.

Question 20 · Deployment

A DevOps engineer is using AWS CloudFormation to deploy a three-tier application. Before executing a stack update that modifies security group rules and replaces an RDS DB instance, the engineer wants to preview exactly which resources will be changed and how (e.g., whether they will be replaced or modified in place). Which CloudFormation feature should the engineer use?

Show answer & explanation

Correct answer: C

  • C. Change sets

Option C is correct. A CloudFormation change set shows a preview of the proposed changes to a stack before execution. It lists each resource that will be added, modified, or replaced, along with the replacement indicator (True/False/Conditional), allowing the engineer to review the impact before committing. Option A is incorrect; drift detection identifies differences between the actual resource state and the CloudFormation template, not the changes that would result from a pending update. Option B is incorrect; StackSets deploy stacks across multiple accounts and regions — they are not a change-preview mechanism. Option D is incorrect; CloudFormation Guard (cfn-guard) is a policy-as-code tool to validate templates against compliance rules, not to preview resource-level changes.

Pick an answer on each question to check it. 20 questions in this test.

185 more DVA-C02 questions

Sign up free to start practising, or subscribe (from $4.97/mo) for the full 205-question bank, flashcards and timed mock exams.

AWS Developer Associate course overview and study guides →