Spring Boot Essentials: Features, Setup Requirements, and Step-by-Step Tutorial

Spring Boot is a widely used framework in the Java ecosystem designed to simplify the process of developing standalone, production-ready applications. It builds on the foundation of the Spring Framework but introduces conventions that significantly reduce boilerplate code and configuration requirements. The primary aim of Spring Boot is to enable developers to focus on building business logic rather than dealing with complex setup or infrastructure concerns. Spring Boot has gained popularity for its ability to streamline Java development, enhance productivity, and support modern application architectures such as microservices.

What is Spring Boot

Spring Boot is an extension of the Spring Framework that provides defaults and opinionated setups to make it easier to create production-ready applications. Unlike the standard Spring Framework, which requires explicit configuration through XML or Java annotations, Spring Boot leverages convention over configuration. This means that the framework comes with sensible defaults for many components, allowing developers to quickly get an application up and running without manually configuring every aspect. Spring Boot integrates seamlessly with the broader Spring ecosystem, offering features such as dependency injection, aspect-oriented programming, and modular design while reducing complexity.

Advantages of Spring Boot

Rapid Development and Prototyping

Spring Boot accelerates the development process by providing pre-configured templates and opinionated defaults. Developers can quickly create prototypes or complete applications without spending significant time on configuration. This rapid development is particularly beneficial in agile environments where iterative delivery and frequent changes are common. The framework’s support for embedded servers, auto-configuration, and ready-to-use components reduces the time required to set up and deploy applications, allowing teams to focus on adding value through business logic.

Simplified Configuration

Spring Boot eliminates the need for verbose XML-based configuration that was common in earlier Spring applications. By relying on annotations and conventions, Spring Boot simplifies application configuration. Developers can configure behavior using properties files or YAML files while relying on auto-configuration to handle defaults. This approach improves code readability and maintainability, reduces the likelihood of errors, and makes it easier for new developers to understand and work with existing projects.

Embedded Server Support

One of the core benefits of Spring Boot is its embedded server capability. By including servers like Tomcat, Jetty, or Undertow within the application, Spring Boot removes the need for external server setup and configuration. This makes deployment simpler and ensures that applications are self-contained and portable. Embedded servers also facilitate rapid testing and continuous integration, allowing developers to run applications quickly in different environments without external dependencies.

Microservices Architecture Facilitation

Spring Boot is particularly suitable for a microservices architecture. Its lightweight and modular design allows developers to create independently deployable services that communicate over RESTful APIs. The framework’s features, such as embedded servers, simplified configuration, and starter dependencies, support the development of distributed systems and microservices efficiently. Spring Boot’s structure promotes modularity and scalability, making it easier to maintain, upgrade, and deploy services in complex enterprise environments.

Limitations of Spring Boot

Complexity for Large-scale Applications

While Spring Boot simplifies development for small to medium applications, managing complexity in large-scale systems can be challenging. The convention-over-configuration approach, although helpful for rapid development, can sometimes restrict fine-grained control over configurations. Developers working on large enterprise applications may need to override default behaviors or implement custom solutions to meet specific requirements, which can increase development complexity.

Learning Curve for Beginners

For beginners, Spring Boot can appear overwhelming due to the number of annotations, tools, and dependencies involved. Understanding the Spring ecosystem, including dependency injection, inversion of control, and Spring-specific design patterns, is essential to effectively use Spring Boot. However, with a structured learning path and hands-on practice, new developers can gradually build proficiency in developing applications with Spring Boot.

Limited Customization Options in Some Cases

Spring Boot’s opinionated defaults can sometimes limit customization. While the framework provides sensible configurations for most use cases, developers requiring highly specialized behavior may need to override these defaults. This can lead to increased complexity or conflicts if custom configurations are not properly managed. Despite this limitation, Spring Boot offers multiple ways to extend and customize its behavior, including properties files, configuration classes, profiles, and external configuration sources.

Goals of Spring Boot

Enhancing Productivity

The primary goal of Spring Boot is to improve developer productivity. By reducing boilerplate code and offering sensible defaults, Spring Boot allows developers to spend less time on repetitive tasks and focus on implementing business logic. Productivity enhancements are also achieved through tools like Spring Boot CLI, embedded servers, and starter dependencies, which simplify project setup and management.

Simplifying Configuration

Spring Boot aims to simplify application configuration. By using auto-configuration, annotations, and external property files, developers can easily define application behavior without writing extensive configuration code. This approach ensures consistency across projects and reduces the risk of misconfiguration while providing the flexibility to override defaults when necessary.

Promoting Convention Over Configuration

Spring Boot emphasizes convention over configuration to reduce the need for explicit setup. This approach standardizes project structure, naming conventions, and component scanning, making applications more predictable and easier to maintain. By following conventions, developers can quickly understand and work with Spring Boot projects, even if they were not involved in the initial setup.

Facilitating Production-Ready Applications

Another key goal of Spring Boot is to simplify the creation of production-ready applications. The framework provides built-in support for monitoring, health checks, metrics, and logging through components like Spring Boot Actuator. Developers can build applications with operational capabilities out of the box, ensuring they meet production standards without requiring extensive additional setup.

Prerequisites for Learning Spring Boot

Before diving into Spring Boot development, it is essential to have a solid foundation in Java programming. Understanding core Java concepts such as object-oriented programming, classes, interfaces, inheritance, polymorphism, exception handling, and collections is crucial. Since Spring Boot builds on the Spring Framework, familiarity with Spring concepts like dependency injection, inversion of control, beans, and annotations will make it easier to grasp Spring Boot’s functionality. Additionally, knowledge of build tools such as Maven or Gradle is necessary because they are commonly used to manage Spring Boot projects. These tools handle dependencies, build lifecycles, and project configurations, simplifying project management. Understanding how to work with Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, or Visual Studio Code is also important, as they provide features such as code completion, debugging, and project structure visualization.

Knowledge of the Java Programming Language

Java serves as the foundation for Spring Boot development. A strong understanding of Java syntax, object-oriented principles, exception handling, collections, and core APIs is required. Developers should be comfortable writing Java classes, methods, and interfaces, and understand how to implement object-oriented design patterns. Knowledge of Java 8 and higher features, including lambda expressions, streams, and optional classes, is highly recommended because many Spring Boot examples and modern practices rely on these features. Familiarity with Java concurrency, multithreading, and memory management is also advantageous for developing scalable applications.

Basics of the Spring Framework

Spring Boot is built on the Spring Framework, so understanding core Spring concepts is essential. These include dependency injection, which allows objects to be created and managed by the Spring container; inversion of control, which decouples object creation from application logic; and aspect-oriented programming, which facilitates cross-cutting concerns such as logging and transaction management. Familiarity with Spring components such as beans, configurations, annotations, and Spring Data is beneficial for leveraging Spring Boot effectively. Understanding how Spring manages the application context and component scanning helps developers create modular, maintainable applications.

Familiarity with Build Tools

Build tools like Maven and Gradle are central to Spring Boot project management. Maven uses a declarative XML file, the pom.xml, to define project dependencies, build configuration, and plugins, while Gradle uses a build. Gradle file with a Groovy or Kotlin DSL for the same purposes. Developers should know how to define dependencies, configure plugins, build projects, and manage multi-module setups. Knowledge of these tools enables efficient project management, simplifies dependency resolution, and integrates seamlessly with Continuous Integration and Continuous Deployment pipelines.

Spring Boot Features

Spring Boot offers a range of features designed to simplify application development. Understanding these features is critical to using the framework effectively.

Auto-Configuration

Auto-configuration automatically configures Spring Boot applications based on the project’s dependencies. It analyses the classpath and sets up necessary beans and components, reducing the need for manual configuration. For example, if a Spring Boot project includes a database dependency, auto-configuration can automatically set up a DataSource bean without explicit configuration. Auto-configuration increases productivity, minimizes boilerplate code, and ensures consistency across projects.

Starter Dependencies

Spring Boot starters are pre-packaged sets of dependencies that simplify project setup. Instead of adding each library manually, developers can use starters to include commonly used dependencies. For instance, spring-boot-starter-web includes dependencies required for building web applications, such as Spring MVC, Tomcat, and Jackson. Starter dependencies reduce configuration effort, streamline development, and make it easier to maintain projects.

Spring Boot CLI

The Spring Boot Command Line Interface allows developers to create and run applications directly from the command line. The CLI supports Groovy-based scripts and provides commands for creating projects, running applications, and testing functionalities without relying on an IDE. This tool is particularly useful for rapid prototyping and experimentation, enabling developers to quickly test concepts and iterate on application designs.

Spring Boot Actuator

Spring Boot Actuator provides production-ready features for monitoring and managing applications. Actuator endpoints offer detailed information about application health, metrics, environment properties, and configuration. Developers can use these endpoints to monitor performance, detect issues, and maintain applications efficiently. Actuator integrates seamlessly with external monitoring systems and can be extended to provide custom metrics and management endpoints.

Spring Boot Security

Spring Boot includes built-in support for securing applications using Spring Security. It simplifies the configuration of authentication, authorization, and access control. Developers can implement security features such as form-based login, OAuth2, and role-based access control with minimal setup. Spring Boot Security ensures that applications are protected against common security vulnerabilities while providing flexibility for customization.

Setting Up a Spring Boot Project

Creating a Spring Boot project is straightforward using Spring Initializr, a web-based tool that generates a pre-configured project structure. Developers can select the project type, build tool, language, Spring Boot version, and required dependencies. The generated project includes the basic directory structure, build files, and necessary dependencies, enabling developers to start coding immediately. After downloading the project, it can be imported into an IDE such as IntelliJ IDEA, Eclipse, or Visual Studio Code for development.

Creating a Simple Spring Boot Application

Once the project is set up, developers create a main application class annotated with @SpringBootApplication. This annotation combines @Configuration, @EnableAutoConfiguration, and @ComponentScan, marking the class as the primary configuration class and enabling auto-configuration and component scanning. Developers can add additional classes, controllers, services, and repositories to implement application logic. The main class contains a main method that invokes SpringApplication.run(), which launches the application, starts the embedded server, and initializes the Spring context.

Understanding the Project Structure

Spring Boot follows a convention-based project structure that enhances maintainability and scalability. The main application class resides in the root package, with additional packages organized by functionality, such as controllers, services, repositories, and configurations. Resources like application.properties or application.yml are stored in the resources folder for configuration purposes. Static assets and templates are placed in designated directories to separate front-end and back-end concerns. Understanding this structure allows developers to navigate projects efficiently, maintain modular code, and follow best practices.

Implementing RESTful Services with Spring Boot

Spring Boot simplifies the creation of RESTful services by providing annotations and built-in components. Developers can define controller classes with @RestController, which combines @Controller and @ResponseBody, allowing methods to return JSON or XML responses directly. HTTP methods such as GET, POST, PUT, and DELETE are mapped using annotations like @GetMapping, @PostMapping, @PutMapping, and @DeleteMapping. Spring Boot handles request routing, content negotiation, and serialization automatically, enabling developers to focus on business logic rather than infrastructure.

Spring Boot Annotations Overview

Annotations play a central role in Spring Boot development. The @SpringBootApplication annotation marks the main application class, while @RestController designates a class as a controller for handling RESTful requests. @GetMapping, @PostMapping, and similar annotations map HTTP requests to methods, and @Autowired enables dependency injection, allowing Spring to manage object creation and wiring. Other annotations like @Service, @Repository, and @Component facilitate component scanning and modular application design. Understanding and using annotations correctly is essential for effective Spring Boot development.

Running and Testing the Application

After setting up the project and creating necessary components, the application can be built and run using the chosen build tool or directly from the IDE. Spring Boot starts an embedded server, such as Tomcat, on the default port 8080, allowing developers to access the application through a browser or API testing tools. Testing endpoints using tools like Postman or cURL ensures that the application functions as expected. Developers can also write unit tests and integration tests using Spring Boot’s testing framework to verify application logic and maintain code quality.

Advanced Configuration in Spring Boot

Spring Boot provides several ways to customize the configuration of applications beyond the defaults provided by auto-configuration. Understanding these advanced configuration options is essential for building robust and flexible applications. Developers can use properties files such as application.properties or application.yml to define application settings, including server ports, logging levels, database connections, and other environment-specific parameters. Profiles allow applications to use different configurations for development, testing, and production environments, enabling seamless environment management. External configuration sources such as environment variables, command-line arguments, and configuration servers can also be used to override default settings, providing greater flexibility for deploying applications in multiple environments.

Programmatic configuration is another powerful feature of Spring Boot. Developers can create Java classes annotated with @Configuration to define beans and configure application behavior directly in code. Conditional configurations can be implemented using annotations like @ConditionalOnProperty, @ConditionalOnClass, and @ConditionalOnMissingBean, which control bean creation based on specific conditions. This enables dynamic configuration and ensures that the application adapts to different environments or runtime requirements. Understanding how to combine property-based, programmatic, and conditional configurations is crucial for building maintainable and scalable applications.

Integrating Spring Boot with Databases

Database integration is a key requirement for most applications. Spring Boot simplifies this process through starter dependencies and auto-configuration. Common relational databases such as MySQL, PostgreSQL, and Oracle are supported, as well as NoSQL databases like MongoDB and Cassandra. By including the appropriate starter dependency, Spring Boot can automatically configure a DataSource, connection pool, and transaction manager, allowing developers to focus on writing business logic rather than database setup.

Spring Boot also integrates seamlessly with Spring Data, a framework that provides abstraction layers for data access. Spring Data JPA enables developers to interact with relational databases using repositories without writing boilerplate SQL. Repository interfaces extend predefined interfaces such as JpaRepository or CrudRepository, providing methods for common operations like save, find, delete, and update. Custom queries can be implemented using JPQL or native SQL when necessary. Spring Boot manages transactions, entity mappings, and database connections automatically, reducing development effort and ensuring consistency.

For NoSQL databases, Spring Boot provides similar abstractions. Spring Data MongoDB, for example, allows developers to define repository interfaces for MongoDB collections and leverage automatic mapping between documents and domain objects. Integration with other databases such as Redis, Cassandra, or Elasticsearch follows a similar pattern, with starter dependencies and auto-configuration handling the underlying setup. Proper database integration ensures data consistency, transaction management, and efficient data access.

Implementing Security in Spring Boot Applications

Security is a critical aspect of modern applications. Spring Boot simplifies application security through built-in integration with Spring Security. Developers can configure authentication, authorization, and access control with minimal setup. By including the spring-boot-starter-security dependency, basic security configurations are automatically applied, including password encoding and HTTP basic authentication.

Developers can create custom security configurations by extending WebSecurityConfigurerAdapter or using the SecurityFilterChain bean in newer Spring Security versions. These configurations allow customization of authentication providers, authorization rules, access control policies, login and logout mechanisms, and session management. Role-based access control enables restricting access to specific endpoints based on user roles, ensuring that sensitive resources are protected.

Spring Boot also supports OAuth2 and JWT-based authentication, enabling secure communication in distributed systems and microservices architectures. Developers can configure authorization servers, resource servers, and token management to implement secure API endpoints. Security testing tools and audit logs further enhance the reliability and integrity of applications, making Spring Boot suitable for enterprise-grade projects requiring robust security measures.

Performance Optimization Techniques

Performance optimization is essential for building scalable applications capable of handling high loads. Spring Boot provides multiple strategies for optimizing performance, including caching, asynchronous processing, database optimization, and resource management.

Caching improves application responsiveness by storing frequently accessed data in memory or external caches such as Redis or Ehcache. Spring Boot supports annotation-based caching using @Cacheable, @CachePut, and @CacheEvict, allowing developers to control caching behavior at the method level. Proper cache configuration reduces database load and improves application performance significantly.

Asynchronous processing allows tasks to run in the background without blocking the main thread. Spring Boot provides the @Async annotation and TaskExecutor configuration to manage asynchronous execution. This approach is useful for resource-intensive operations, external service calls, and parallel processing, ensuring that the application remains responsive under heavy load.

Database optimization is another critical area. Proper indexing, query optimization, connection pooling, and batch processing improve database performance. Spring Boot simplifies connection pooling and transaction management using HikariCP or other connection pool implementations. Monitoring slow queries and optimizing SQL statements further enhances performance and scalability.

Monitoring and profiling are essential for identifying performance bottlenecks. Spring Boot Actuator provides metrics for memory usage, thread activity, HTTP requests, database connections, and cache performance. Developers can integrate Actuator with monitoring tools to visualize and analyze application performance, enabling proactive optimization and ensuring high availability.

Advanced RESTful Service Implementation

Spring Boot enables advanced RESTful service development through features such as content negotiation, exception handling, versioning, and hypermedia support. Content negotiation allows applications to respond with different formats, such as JSON, XML, or custom media types, based on client requests. Exception handling can be standardized using @ControllerAdvice and @ExceptionHandler annotations, ensuring consistent error responses across endpoints.

API versioning is essential for maintaining backward compatibility as applications evolve. Spring Boot supports versioning through URI paths, request parameters, or headers, allowing developers to release new versions of APIs without disrupting existing clients. Hypermedia as the Engine of Application State (HATEOAS) provides additional metadata and navigation information in responses, improving API usability and client integration.

Security and validation are integrated into RESTful services using Spring Security and Bean Validation (JSR 380). Input validation using annotations like @Valid, @NotNull, @Size, and custom validators ensures data integrity and prevents malicious input. Cross-origin resource sharing (CORS) configurations enable controlled access for web applications and microservices.

Testing and Quality Assurance

Testing is a critical part of Spring Boot development. The framework provides extensive support for unit testing, integration testing, and end-to-end testing. JUnit and Mockito are commonly used for unit tests, allowing developers to verify individual components and service logic. Spring Boot testing annotations such as @SpringBootTest, @WebMvcTest, @DataJpaTest, and @MockBean facilitate context loading, controller testing, repository testing, and dependency mocking.

Integration tests ensure that multiple components work together correctly, verifying application behavior in realistic scenarios. Test profiles and in-memory databases like H2 can be used to isolate test environments and maintain reproducibility. Continuous Integration pipelines can run automated tests during build and deployment, ensuring consistent quality.

Performance testing, load testing, and stress testing are essential for validating scalability. Tools like JMeter, Gatling, or Spring Boot Actuator metrics provide insights into response times, throughput, and resource utilization, allowing developers to fine-tune the application for production environments.

Spring Boot in Microservices Architecture

Spring Boot is widely used in microservices development due to its lightweight nature, modularity, and built-in support for RESTful services. Each microservice can be developed, tested, and deployed independently, reducing complexity in large systems. Spring Boot’s integration with Spring Cloud adds features such as service discovery, configuration management, distributed tracing, and circuit breakers, enabling resilient and scalable microservices ecosystems.

Developers can deploy Spring Boot microservices using containerization tools such as Docker and orchestrate them with Kubernetes. Embedded servers, externalized configurations, and monitoring endpoints ensure that each microservice operates independently while maintaining observability. Communication between services can be achieved using REST APIs, messaging queues, or event-driven architectures, providing flexibility in design and deployment strategies.

Monitoring and Observability

Observability is a key aspect of maintaining production-grade applications. Spring Boot Actuator provides endpoints for health checks, metrics, environment information, thread dumps, and loggers. These endpoints can be customized and secured for monitoring purposes. Integrating the Actuator with external monitoring and alerting systems allows developers to detect issues, track performance trends, and take corrective actions proactively. Logging frameworks such as Logback, Log4j2, or SLF4J provide detailed application logs, supporting debugging, auditing, and operational analysis.

Application metrics, combined with monitoring dashboards, give real-time visibility into system performance. Developers can track memory usage, CPU utilization, database connection pools, response times, error rates, and cache efficiency, enabling continuous performance tuning and proactive maintenance.

Troubleshooting Common Spring Boot Issues

Effective troubleshooting is critical to maintaining robust Spring Boot applications.

Application Fails to Start

If the application fails to start, common causes include incorrect dependency versions, port conflicts, missing configuration files, or incompatible Java versions. Reviewing the startup logs, verifying dependency versions, checking the build tool configuration, and ensuring correct environment settings are essential steps in resolving startup issues.

Bean Creation Errors

Bean creation errors occur when Spring fails to instantiate a bean due to missing dependencies, circular references, or misconfigured annotations. Solutions include reviewing @Autowired dependencies, using @Primary or @Qualifier to resolve conflicts, and checking component scanning paths to ensure all required beans are detected.

Database Connectivity Issues

Database connectivity issues often arise from incorrect connection URLs, missing drivers, authentication failures, or network problems. Verifying connection properties, ensuring the database is running, and testing with database clients can help identify the root cause. Spring Boot’s logging can provide detailed information about connection attempts and errors.

Security Configuration Problems

Security-related issues may occur if roles, authentication providers, or endpoint permissions are misconfigured. Reviewing WebSecurityConfigurerAdapter configurations, checking user roles, and validating authentication mechanisms such as OAuth2 or JWT can resolve common security problems. Using test endpoints and monitoring logs ensures proper access control.

Performance Bottlenecks

Performance issues can result from inefficient queries, lack of caching, blocking operations, or resource contention. Using Spring Boot Actuator metrics, profiling tools, and database query analysis can identify bottlenecks. Applying caching, asynchronous processing, database optimization, and efficient code design improves application performance.

Best Practices for Spring Boot Development

Following best practices ensures that Spring Boot applications are maintainable, scalable, and secure.

Modular Project Structure

Organize projects into modules such as controllers, services, repositories, and configurations. This structure enhances code readability, maintainability, and scalability, especially for larger applications.

Use Auto-Configuration Wisely

Rely on Spring Boot’s auto-configuration to reduce boilerplate code, but understand when to override defaults. Custom configurations should be applied only when necessary to maintain clarity and reduce complexity.

Implement Proper Logging

Use logging frameworks such as Logback, Log4j2, or SLF4J to capture application events, errors, and debug information. Structured logging and consistent log levels improve monitoring and troubleshooting.

Secure Applications

Integrate Spring Security for authentication, authorization, and access control. Use role-based access, secure passwords, token-based authentication, and HTTPS for secure communication. Regularly update dependencies to patch vulnerabilities.

Testing and Continuous Integration

Write unit tests, integration tests, and end-to-end tests to ensure code quality. Integrate automated tests into Continuous Integration pipelines for consistent verification of functionality. Use in-memory databases and test profiles for isolated testing.

Monitor and Profile Applications

Use Spring Boot Actuator and external monitoring tools to track metrics, health, and performance. Profiling helps identify bottlenecks and optimize resource usage for production environments.

Deployment Strategies for Spring Boot Applications

Spring Boot applications can be deployed in multiple ways depending on project requirements and environment constraints.

Standalone Deployment

Spring Boot applications with embedded servers can be deployed as standalone JAR files. The JAR contains all dependencies and can be executed using the java -jar command. This approach simplifies deployment and eliminates external server requirements.

Containerization with Docker

Docker enables packaging Spring Boot applications into lightweight, portable containers. Applications can run consistently across different environments, including development, testing, and production. Docker images include the JAR file, runtime, and configuration, ensuring reproducibility.

Cloud Deployment

Spring Boot applications are well-suited for cloud deployment. Platforms such as AWS, Azure, and Google Cloud provide services for running Spring Boot applications with scalable infrastructure. Using container orchestration platforms like Kubernetes allows automated deployment, scaling, and management microservice applicationssons.

Continuous Deployment

Integrating Spring Boot with Continuous Integration and Deployment pipelines ensures automated testing, building, and deployment. Tools like Jenkins, GitHub Actions, and GitLab CI/CD enable seamless delivery of applications, reducing human error and accelerating release cycles.

Practical Examples of Spring Boot Applications

Spring Boot can be used to build a wide range of applications. Examples include web applications, RESTful APIs, microservices, data-driven applications, batch processing systems, and real-time monitoring tools.

Web applications leverage Spring MVC with Thymeleaf or JSP for rendering views, while REST APIs use @RestController and JSON responses for client-server communication. Microservices architectures use Spring Boot for creating independently deployable services with communication through REST, messaging, or event-driven patterns. Data-driven applications integrate with relational or NoSQL databases, applying JPA or Spring Data repositories for efficient data access. Batch processing and scheduling are implemented using Spring Batch and @Scheduled annotations.

Practical development emphasizes modular design, testing, security, monitoring, and deployment. By applying Spring Boot features, developers can build robust, maintainable, and scalable applications suitable for production environments.

Conclusion

Spring Boot is a comprehensive framework that simplifies Java application development. By providing defaults, auto-configuration, embedded servers, starter dependencies, and production-ready features, it enables rapid development and deployment. Understanding core concepts, advanced configurations, database integration, security, performance optimization, testing, deployment strategies, and best practices ensures that developers can build robust and scalable applications. Whether for web applications, RESTful services, microservices, or cloud deployment, Spring Boot provides the tools and conventions necessary to deliver high-quality software efficiently. With hands-on practice, continuous learning, and adherence to best practices, developers can master Spring Boot and create production-ready applications for modern enterprise environments.