diff --git a/discord/client.py b/discord/client.py
index ff02bf7b6..8ecff6ec2 100644
--- a/discord/client.py
+++ b/discord/client.py
@@ -53,7 +53,7 @@ from .user import User, ClientUser
 from .invite import Invite
 from .template import Template
 from .widget import Widget
-from .guild import Guild
+from .guild import Guild, GuildPreview
 from .emoji import Emoji
 from .channel import _threaded_channel_factory, PartialMessageable
 from .enums import ChannelType, EntitlementOwnerType
@@ -2356,6 +2356,29 @@ class Client:
         data = await self.http.get_guild(guild_id, with_counts=with_counts)
         return Guild(data=data, state=self._connection)
 
+    async def fetch_guild_preview(self, guild_id: int) -> GuildPreview:
+        """|coro|
+
+        Retrieves a preview of a :class:`.Guild` from an ID. If the guild is discoverable,
+        you don't have to be a member of it.
+
+        .. versionadded:: 2.5
+
+        Raises
+        ------
+        NotFound
+            The guild doesn't exist, or is not discoverable and you are not in it.
+        HTTPException
+            Getting the guild failed.
+
+        Returns
+        --------
+        :class:`.GuildPreview`
+            The guild preview from the ID.
+        """
+        data = await self.http.get_guild_preview(guild_id)
+        return GuildPreview(data=data, state=self._connection)
+
     async def create_guild(
         self,
         *,
diff --git a/discord/guild.py b/discord/guild.py
index fc39179ab..faf64e279 100644
--- a/discord/guild.py
+++ b/discord/guild.py
@@ -99,6 +99,7 @@ from .soundboard import SoundboardSound
 
 __all__ = (
     'Guild',
+    'GuildPreview',
     'BanEntry',
 )
 
@@ -109,6 +110,7 @@ if TYPE_CHECKING:
     from .types.guild import (
         Ban as BanPayload,
         Guild as GuildPayload,
+        GuildPreview as GuildPreviewPayload,
         RolePositionUpdate as RolePositionUpdatePayload,
         GuildFeature,
         IncidentData,
@@ -160,6 +162,121 @@ class _GuildLimit(NamedTuple):
     filesize: int
 
 
+class GuildPreview(Hashable):
+    """Represents a preview of a Discord guild.
+
+        .. versionadded:: 2.5
+
+    .. container:: operations
+
+        .. describe:: x == y
+
+            Checks if two guild previews are equal.
+
+        .. describe:: x != y
+
+            Checks if two guild previews are not equal.
+
+        .. describe:: hash(x)
+
+            Returns the guild's hash.
+
+        .. describe:: str(x)
+
+            Returns the guild's name.
+
+    Attributes
+    ----------
+    name: :class:`str`
+        The guild preview's name.
+    id: :class:`int`
+        The guild preview's ID.
+    features: List[:class:`str`]
+        A list of features the guild has. See :attr:`Guild.features` for more information.
+    description: Optional[:class:`str`]
+        The guild preview's description.
+    emojis: Tuple[:class:`Emoji`, ...]
+        All emojis that the guild owns.
+    stickers: Tuple[:class:`GuildSticker`, ...]
+        All stickers that the guild owns.
+    approximate_member_count: :class:`int`
+        The approximate number of members in the guild.
+    approximate_presence_count: :class:`int`
+        The approximate number of members currently active in in the guild. Offline members are excluded.
+    """
+
+    __slots__ = (
+        '_state',
+        '_icon',
+        '_splash',
+        '_discovery_splash',
+        'id',
+        'name',
+        'emojis',
+        'stickers',
+        'features',
+        'description',
+        "approximate_member_count",
+        "approximate_presence_count",
+    )
+
+    def __init__(self, *, data: GuildPreviewPayload, state: ConnectionState) -> None:
+        self._state: ConnectionState = state
+        self.id = int(data['id'])
+        self.name: str = data['name']
+        self._icon: Optional[str] = data.get('icon')
+        self._splash: Optional[str] = data.get('splash')
+        self._discovery_splash: Optional[str] = data.get('discovery_splash')
+        self.emojis: Tuple[Emoji, ...] = tuple(
+            map(
+                lambda d: Emoji(guild=state._get_or_create_unavailable_guild(self.id), state=state, data=d),
+                data.get('emojis', []),
+            )
+        )
+        self.stickers: Tuple[GuildSticker, ...] = tuple(
+            map(lambda d: GuildSticker(state=state, data=d), data.get('stickers', []))
+        )
+        self.features: List[GuildFeature] = data.get('features', [])
+        self.description: Optional[str] = data.get('description')
+        self.approximate_member_count: int = data.get('approximate_member_count')
+        self.approximate_presence_count: int = data.get('approximate_presence_count')
+
+    def __str__(self) -> str:
+        return self.name
+
+    def __repr__(self) -> str:
+        return (
+            f'<{self.__class__.__name__} id={self.id} name={self.name!r} description={self.description!r} '
+            f'features={self.features}>'
+        )
+
+    @property
+    def created_at(self) -> datetime.datetime:
+        """:class:`datetime.datetime`: Returns the guild's creation time in UTC."""
+        return utils.snowflake_time(self.id)
+
+    @property
+    def icon(self) -> Optional[Asset]:
+        """Optional[:class:`Asset`]: Returns the guild's icon asset, if available."""
+        if self._icon is None:
+            return None
+        return Asset._from_guild_icon(self._state, self.id, self._icon)
+
+    @property
+    def splash(self) -> Optional[Asset]:
+        """Optional[:class:`Asset`]: Returns the guild's invite splash asset, if available."""
+        if self._splash is None:
+            return None
+        return Asset._from_guild_image(self._state, self.id, self._splash, path='splashes')
+
+    @property
+    def discovery_splash(self) -> Optional[Asset]:
+        """Optional[:class:`Asset`]: Returns the guild's discovery splash asset, if available."""
+        if self._discovery_splash is None:
+            return None
+        return Asset._from_guild_image(self._state, self.id, self._discovery_splash, path='discovery-splashes')
+
+
 class Guild(Hashable):
     """Represents a Discord guild.
 
diff --git a/discord/http.py b/discord/http.py
index 7c3f198c9..5cb6cb58c 100644
--- a/discord/http.py
+++ b/discord/http.py
@@ -1453,6 +1453,9 @@ class HTTPClient:
         params = {'with_counts': int(with_counts)}
         return self.request(Route('GET', '/guilds/{guild_id}', guild_id=guild_id), params=params)
 
+    def get_guild_preview(self, guild_id: Snowflake) -> Response[guild.GuildPreview]:
+        return self.request(Route('GET', '/guilds/{guild_id}/preview', guild_id=guild_id))
+
     def delete_guild(self, guild_id: Snowflake) -> Response[None]:
         return self.request(Route('DELETE', '/guilds/{guild_id}', guild_id=guild_id))
 
diff --git a/docs/api.rst b/docs/api.rst
index ca0fb4ef4..0b4015f78 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -4815,6 +4815,13 @@ Guild
 
         :type: List[:class:`Object`]
 
+GuildPreview
+~~~~~~~~~~~~
+
+.. attributetable:: GuildPreview
+
+.. autoclass:: GuildPreview
+    :members:
 
 ScheduledEvent
 ~~~~~~~~~~~~~~