Implementing Singleton Pattern in Go
James Reed
Infrastructure Engineer · Leapcell

Key Takeaways
sync.Once
ensures safe and efficient singleton initialization.- The
init
function allows eager initialization at package load. sync.Mutex
enables thread-safe lazy initialization.
The Singleton pattern is a design pattern that ensures a class has only one instance and provides a global point of access to it. This pattern is particularly useful when exactly one object is needed to coordinate actions across a system.
In Go, implementing the Singleton pattern can be achieved in various ways. Below are some common methods:
Using sync.Once
Go's sync
package provides the Once
type, which ensures that a piece of code is executed only once. This is particularly useful for implementing the Singleton pattern.
package singleton import ( "sync" ) type Singleton struct { // Add fields here } var ( instance *Singleton once sync.Once ) func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{ // Initialize fields here } }) return instance }
In this implementation:
sync.Once
ensures that the initialization function runs only once, making it safe for concurrent use.- The
GetInstance
function returns the singleton instance, initializing it if it hasn't been already.
Using init
Function
Go's init
function is called automatically when the package is initialized. This can be leveraged to create a Singleton.
package singleton type Singleton struct { // Add fields here } var instance *Singleton func init() { instance = &Singleton{ // Initialize fields here } } func GetInstance() *Singleton { return instance }
In this approach:
- The
init
function initializes the singleton instance when the package is loaded. - The
GetInstance
function provides access to the singleton instance.
Using sync.Mutex
For scenarios where lazy initialization is desired without using sync.Once
, a mutex can be employed to ensure thread safety.
package singleton import ( "sync" ) type Singleton struct { // Add fields here } var ( instance *Singleton mutex sync.Mutex ) func GetInstance() *Singleton { if instance == nil { mutex.Lock() defer mutex.Unlock() if instance == nil { instance = &Singleton{ // Initialize fields here } } } return instance }
In this implementation:
- A mutex is used to synchronize access to the instance creation.
- Double-checked locking is applied to prevent multiple initializations.
Considerations
When implementing the Singleton pattern in Go, consider the following:
- Thread Safety: Ensure that the singleton instance is created in a thread-safe manner, especially in concurrent applications.
- Lazy vs. Eager Initialization: Decide whether the instance should be created at program startup (eager) or when it's first needed (lazy).
- Testing: Singleton patterns can introduce challenges in testing due to their global state. Consider interfaces and dependency injection to mitigate this.
By carefully choosing the appropriate implementation method, you can effectively utilize the Singleton pattern in your Go applications to ensure a single, globally accessible instance of a particular type.
FAQs
sync.Once
ensures initialization runs only once, avoiding unnecessary locking overhead.
Use init
for eager initialization when the singleton is required immediately upon package load.
It first checks if the instance exists before locking, reducing unnecessary synchronization.
We are Leapcell, your top choice for hosting Go projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ